Skip to content

Commit

Permalink
Better error messages for IR loader failures (#48)
Browse files Browse the repository at this point in the history
* More error codes related for loading WAV files

* Better error messages

* Add enum of return codes and capture IR loading in IR state

* Error messages for failed IR loads.
  • Loading branch information
sdatkinson authored Jan 29, 2023
1 parent 15279d9 commit b19f043
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 43 deletions.
76 changes: 63 additions & 13 deletions NeuralAmpModeler/NeuralAmpModeler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,47 @@ NeuralAmpModeler::NeuralAmpModeler(const InstanceInfo& info)
pGraphics->PromptForFile(fileName, path);
if (fileName.GetLength()) {
this->mIRPath = path;
this->_GetIR(fileName);
const dsp::wav::LoadReturnCode retCode = this->_GetIR(fileName);
if (retCode != dsp::wav::LoadReturnCode::SUCCESS) {
std::stringstream message;
message << "Failed to load IR file " << fileName.Get() << ":\n";
switch (retCode) {
case (dsp::wav::LoadReturnCode::ERROR_OPENING):
message << "Failed to open file (is it being used by another program?)";
break;
case (dsp::wav::LoadReturnCode::ERROR_NOT_RIFF):
message << "File is not a WAV file.";
break;
case (dsp::wav::LoadReturnCode::ERROR_NOT_WAVE):
message << "File is not a WAV file.";
break;
case (dsp::wav::LoadReturnCode::ERROR_MISSING_FMT):
message << "File is missing expected format chunk.";
break;
case (dsp::wav::LoadReturnCode::ERROR_INVALID_FILE):
message << "WAV file contents are invalid.";
break;
case (dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_IEEE_FLOAT):
message << "Unsupported file format \"IEEE float\"";
break;
case (dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_ALAW):
message << "Unsupported file format \"A-law\"";
break;
case (dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_MULAW):
message << "Unsupported file format \"mu-law\"";
break;
case (dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_EXTENSIBLE):
message << "Unsupported file format \"extensible\"";
break;
case (dsp::wav::LoadReturnCode::ERROR_NOT_MONO):
message << "File is not mono.";
break;
case (dsp::wav::LoadReturnCode::ERROR_OTHER):
message << "???";
break;
}
pGraphics->ShowMessageBox(message.str().c_str(), "Failed to load IR!", kMB_OK);
}
}
};

Expand Down Expand Up @@ -489,26 +529,36 @@ void NeuralAmpModeler::_GetDSP(const WDL_String& modelPath)
}
}

void NeuralAmpModeler::_GetIR(const WDL_String& irFileName)
dsp::wav::LoadReturnCode NeuralAmpModeler::_GetIR(const WDL_String& irFileName)
{
WDL_String previousIRFileName;

previousIRFileName = this->mIRFileName;
const double sampleRate = this->GetSampleRate();
dsp::wav::LoadReturnCode wavState = dsp::wav::LoadReturnCode::ERROR_OTHER;
try {
previousIRFileName = this->mIRFileName;
const double sampleRate = this->GetSampleRate();
this->mStagedIR = std::make_unique<dsp::ImpulseResponse>(irFileName, sampleRate);
this->_SetIRMsg(irFileName);
wavState = this->mStagedIR->GetWavState();
}
catch (std::exception& e) {
std::stringstream ss;
ss << "FAILED to load IR";
SendControlMsgFromDelegate(kCtrlTagIRName, 0, int(strlen(ss.str().c_str())), ss.str().c_str());
if (this->mStagedIR != nullptr) {
this->mStagedIR = nullptr;
}
this->mIRFileName = previousIRFileName;
std::cerr << "Failed to read IR" << std::endl;
wavState = dsp::wav::LoadReturnCode::ERROR_OTHER;
std::cerr << "Caught unhandled exception while attempting to load IR:" << std::endl;
std::cerr << e.what() << std::endl;
}

if (wavState == dsp::wav::LoadReturnCode::SUCCESS)
this->_SetIRMsg(irFileName);
else {
if (this->mStagedIR != nullptr) {
this->mStagedIR = nullptr;
}
this->mIRFileName = previousIRFileName;
std::stringstream ss;
ss << "FAILED to load IR";
SendControlMsgFromDelegate(kCtrlTagIRName, 0, int(strlen(ss.str().c_str())), ss.str().c_str());
}

return wavState;
}

size_t NeuralAmpModeler::_GetBufferNumChannels() const
Expand Down
4 changes: 3 additions & 1 deletion NeuralAmpModeler/NeuralAmpModeler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

#include "ISender.h"

#include "dsp/wav.h"

const int kNumPresets = 1;

enum EParams
Expand Down Expand Up @@ -68,7 +70,7 @@ class NeuralAmpModeler final : public iplug::Plugin
// Gets a new DSP object and stores it to mStagedDSP
void _GetDSP(const WDL_String& dspPath);
// Gets the IR and stores to mStagedIR
void _GetIR(const WDL_String& irFileName);
dsp::wav::LoadReturnCode _GetIR(const WDL_String& irFileName);
// Update the message about which model is loaded.
void _SetModelMsg(const WDL_String& dspPath);
bool _HaveModel() const {
Expand Down
18 changes: 10 additions & 8 deletions NeuralAmpModeler/dsp/ImpulseResponse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
#include "ImpulseResponse.h"

dsp::ImpulseResponse::ImpulseResponse(const WDL_String& fileName,
const double sampleRate)
const double sampleRate):
mWavState(dsp::wav::LoadReturnCode::ERROR_OTHER)
{
// Try to load the WAV
if (dsp::wav::Load(fileName, this->mRawAudio, this->mRawAudioSampleRate) != dsp::wav::RET_SUCCESS) {
std::stringstream ss;
ss << "Failed to load IR at " << fileName.Get() << std::endl;
throw std::runtime_error(ss.str());
}
// Set the weights based on the raw audio.
this->_SetWeights(sampleRate);
this->mWavState = dsp::wav::Load(fileName, this->mRawAudio, this->mRawAudioSampleRate);
if (this->mWavState != dsp::wav::LoadReturnCode::SUCCESS) {
std::stringstream ss;
ss << "Failed to load IR at " << fileName.Get() << std::endl;
}
else
// Set the weights based on the raw audio.
this->_SetWeights(sampleRate);
}

iplug::sample** dsp::ImpulseResponse::Process(iplug::sample** inputs,
Expand Down
5 changes: 5 additions & 0 deletions NeuralAmpModeler/dsp/ImpulseResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "wdlstring.h" // WDL_String
#include "IPlugConstants.h" // sample
#include "dsp.h"
#include "wav.h"

namespace dsp {
class ImpulseResponse : public History {
Expand All @@ -24,10 +25,14 @@ namespace dsp {
iplug::sample** Process(iplug::sample** inputs,
const size_t numChannels,
const size_t numFrames) override;
// TODO states for the IR class
dsp::wav::LoadReturnCode GetWavState() const { return this->mWavState; };
private:
// Set the weights, given that the plugin is running at the provided sample rate.
void _SetWeights(const double sampleRate);

// State of audio
dsp::wav::LoadReturnCode mWavState;
// Keep a copy of the raw audio that was loaded so that it can be resampled
std::vector<float> mRawAudio;
double mRawAudioSampleRate;
Expand Down
45 changes: 31 additions & 14 deletions NeuralAmpModeler/dsp/wav.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ void ReadChunkAndSkipJunk(std::ifstream& file, char* chunkID)
throw std::runtime_error("Found more than 1 junk chunk");
}

int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double &sampleRate)
dsp::wav::LoadReturnCode dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double &sampleRate)
{
// FYI: https://www.mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
// Open the WAV file for reading
Expand All @@ -43,16 +43,16 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
// Check if the file was opened successfully
if (!wavFile.is_open()) {
std::cerr << "Error opening WAV file" << std::endl;
return dsp::wav::RET_ERROR_OPENING;
return dsp::wav::LoadReturnCode::ERROR_OPENING;
}

// WAV file has 3 "chunks": RIFF ("RIFF"), format ("fmt ") and data ("data").
// Read the WAV file header
char chunkId[4];
ReadChunkAndSkipJunk(wavFile, chunkId);
if (strncmp(chunkId, "RIFF", 4) != 0) {
std::cerr << "Error: Not a WAV file" << std::endl;
return dsp::wav::RET_ERROR_NOT_WAV;
std::cerr << "Error: File does not start with expected RIFF chunk. Got" << chunkId << " instead." << std::endl;
return dsp::wav::LoadReturnCode::ERROR_NOT_RIFF;
}

int chunkSize;
Expand All @@ -61,16 +61,16 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
char format[4];
wavFile.read(format, 4);
if (strncmp(format, "WAVE", 4) != 0) {
std::cerr << "Error: Not a WAV file" << std::endl;
return dsp::wav::RET_ERROR_NOT_WAV;
std::cerr << "Error: Files' second chunk (format) is not expected WAV. Got" << format << " instead." << std::endl;
return dsp::wav::LoadReturnCode::ERROR_NOT_WAVE;
}

// Read the format chunk
char subchunk1Id[4];
ReadChunkAndSkipJunk(wavFile, subchunk1Id);
if (strncmp(subchunk1Id, "fmt ", 4) != 0) {
std::cerr << "Error: Invalid WAV file" << std::endl;
return dsp::wav::RET_ERROR_INVALID_WAV;
std::cerr << "Error: Invalid WAV file missing expected fmt section; got " << subchunk1Id << " instead." << std::endl;
return dsp::wav::LoadReturnCode::ERROR_MISSING_FMT;
}

int subchunk1Size;
Expand All @@ -79,16 +79,33 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
unsigned short audioFormat;
wavFile.read(reinterpret_cast<char*>(&audioFormat), 2);
if (audioFormat != 1) {
std::cerr << "Error: Only PCM format is supported" << std::endl;
return dsp::wav::RET_ERROR_NOT_PCM;
std::cerr << "Error: Only PCM format is supported.";
switch (audioFormat)
{
case 3:
std::cerr << "(Got: IEEE float)" << std::endl;
return dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_IEEE_FLOAT;
case 6:
std::cerr << "(Got: A-law)" << std::endl;
return dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_ALAW;
case 7:
std::cerr << "(Got: mu-law)" << std::endl;
return dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_MULAW;
case 65534:
std::cerr << "(Got: Extensible)" << std::endl;
return dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_FORMAT_EXTENSIBLE;
default:
std::cerr << "(Got unknown format " << audioFormat << ")" << std::endl;
return dsp::wav::LoadReturnCode::ERROR_INVALID_FILE;
}
}

short numChannels;
wavFile.read(reinterpret_cast<char*>(&numChannels), 2);
// HACK
if (numChannels != 1) {
std::cerr << "Require mono (using for IR loading)" << std::endl;
return dsp::wav::RET_ERROR_INVALID_WAV;
return dsp::wav::LoadReturnCode::ERROR_NOT_MONO;
}

int iSampleRate;
Expand All @@ -110,7 +127,7 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
ReadChunkAndSkipJunk(wavFile, subchunk2Id);
if (strncmp(subchunk2Id, "data", 4) != 0) {
std::cerr << "Error: Invalid WAV file" << std::endl;
return dsp::wav::RET_ERROR_INVALID_WAV;
return dsp::wav::LoadReturnCode::ERROR_INVALID_FILE;
}

// Size of the data chunk, in bits.
Expand All @@ -125,7 +142,7 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
dsp::wav::_LoadSamples32(wavFile, subchunk2Size, audio);
else {
std::cerr << "Error: Unsupported bits per sample: " << bitsPerSample << std::endl;
return 1;
return dsp::wav::LoadReturnCode::ERROR_UNSUPPORTED_BITS_PER_SAMPLE;
}

// Close the WAV file
Expand All @@ -134,7 +151,7 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
// Print the number of samples
// std::cout << "Number of samples: " << samples.size() << std::endl;

return dsp::wav::RET_SUCCESS;
return dsp::wav::LoadReturnCode::SUCCESS;
}

void dsp::wav::_LoadSamples16(std::ifstream &wavFile,
Expand Down
23 changes: 16 additions & 7 deletions NeuralAmpModeler/dsp/wav.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,26 @@

namespace dsp {
namespace wav {
// Return cases
const int RET_SUCCESS = 0;
const int RET_ERROR_OPENING = 1;
const int RET_ERROR_NOT_WAV = 2;
const int RET_ERROR_INVALID_WAV = 3;
const int RET_ERROR_NOT_PCM = 4;
enum class LoadReturnCode {
SUCCESS = 0,
ERROR_OPENING,
ERROR_NOT_RIFF,
ERROR_NOT_WAVE,
ERROR_MISSING_FMT,
ERROR_INVALID_FILE,
ERROR_UNSUPPORTED_FORMAT_IEEE_FLOAT,
ERROR_UNSUPPORTED_FORMAT_ALAW,
ERROR_UNSUPPORTED_FORMAT_MULAW,
ERROR_UNSUPPORTED_FORMAT_EXTENSIBLE,
ERROR_UNSUPPORTED_BITS_PER_SAMPLE,
ERROR_NOT_MONO,
ERROR_OTHER
};
// Load a WAV file into a provided array of doubles,
// And note the sample rate.
//
// Returns: as per return cases above
int Load(const WDL_String& fileName, std::vector<float> &audio, double& sampleRate);
LoadReturnCode Load(const WDL_String& fileName, std::vector<float> &audio, double& sampleRate);

// Load samples, 16-bit
void _LoadSamples16(std::ifstream &wavFile, const int chunkSize, std::vector<float>& samples);
Expand Down

0 comments on commit b19f043

Please sign in to comment.