commit b19f0436b325b02d4986b69467d149fc1d018c8f
parent 15279d91d092a338cc67b3fdbdcd23d040dbbe41
Author: Steven Atkinson <steven@atkinson.mn>
Date: Sat, 28 Jan 2023 18:33:05 -0800
Better error messages for IR loader failures (#48)
* 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.
Diffstat:
6 files changed, 128 insertions(+), 43 deletions(-)
diff --git a/NeuralAmpModeler/NeuralAmpModeler.cpp b/NeuralAmpModeler/NeuralAmpModeler.cpp
@@ -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);
+ }
}
};
@@ -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
diff --git a/NeuralAmpModeler/NeuralAmpModeler.h b/NeuralAmpModeler/NeuralAmpModeler.h
@@ -10,6 +10,8 @@
#include "ISender.h"
+#include "dsp/wav.h"
+
const int kNumPresets = 1;
enum EParams
@@ -68,7 +70,7 @@ private:
// 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 {
diff --git a/NeuralAmpModeler/dsp/ImpulseResponse.cpp b/NeuralAmpModeler/dsp/ImpulseResponse.cpp
@@ -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,
diff --git a/NeuralAmpModeler/dsp/ImpulseResponse.h b/NeuralAmpModeler/dsp/ImpulseResponse.h
@@ -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 {
@@ -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;
diff --git a/NeuralAmpModeler/dsp/wav.cpp b/NeuralAmpModeler/dsp/wav.cpp
@@ -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
@@ -43,7 +43,7 @@ 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").
@@ -51,8 +51,8 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
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;
@@ -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;
@@ -79,8 +79,25 @@ 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;
@@ -88,7 +105,7 @@ int dsp::wav::Load(const WDL_String &fileName, std::vector<float> &audio, double
// 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;
@@ -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.
@@ -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
@@ -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,
diff --git a/NeuralAmpModeler/dsp/wav.h b/NeuralAmpModeler/dsp/wav.h
@@ -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);