/* RDAIFFPP version 0.16, december 30, 2019, a C++ class to read AIFF files. Latest version at: https://ecomaan.nl/cpp/rdaiffpp Test the RDAIFF class using the provided test-files: a.aiff = 16-bit quadrophonic. b.aiff = 8-bit stereo (not yet used). Input files are expected in current directory. Only a couple of things are tested here. */ #include #include // For abs(). using namespace std; #include "rdaiff.hpp" /* Test the presence and the complete contents of a small testfile (a.aiff). Returns zero when test succeeded, nonzero when failed. */ int contents_a() { cout << "Test contents_a():\n"; try { const int n_frames = 9; const int n_channels = 4; const short test_pattern[n_frames][n_channels] = { { 0, -3, -2, 1 }, { -1, 2, 3, 0 }, { 16384, -16384, 3000, -3000 }, { -16383, -4, 4, 16383 }, { 32767, -32767, 0, -32768 }, { 126, 127, 128, 129 }, { 257, 256, 255, 254 }, { 16385, -255, -16385, -256 }, { -126, -127, -128, -129 } }; short frame[n_channels]; RDAIFF a("a.aiff"); // 16-bit, quadrophonic, 32 Khz, 9 frames. if ((a.frames() == n_frames) && (a.channels() == n_channels) && (a.bits() == 16) && (a.samplerate() == 32000.0)) cout << " OK: AIFF header.\n"; else cout << " ERORR: wrong contents in AIFF header!\n"; for (short i = 0; i < n_frames; i++) { a.read(frame, 1); for (short j = 0; j < n_channels; j++) { if (frame[j] != test_pattern[i][j]) { cout << " ERORR: mismatch in sampleframe " << i << ", channel " << j << "!\n"; return 1; } } cout << " OK: checked sampleframe " << i << ".\n"; } return 0; } catch (const char* err_txt) { cout << " " << err_txt << "\n"; return 1; } } /* Test whether an attemp to read 16-bit samples into a single byte (char) really throws an exception. Returns zero when test succeeded, nonzero when failed. */ int nonfit_a() { const short max_ch = 4; RDAIFF a; int e; cout << "Test nonfit_a():\n"; try { a.open("a.aiff"); // 16-bit quadrophonic. if (a.channels() > max_ch) { cout << " Sorry, channels > " << max_ch << "!\n"; return 1; // (File is closed automatically.) } } catch (const char* err_txt) { cout << " " << err_txt << "\n Could not open '" << a.name() << "'!\n"; return 1; // Despite failure, filename is copied into object. } try { signed char frame[max_ch]; a.read(frame, 1); // Not supposed to fit, expected to fail. cout << " ERROR: possible data-loss exception expected!\n"; e = 1; } catch (const char* err_txt) { cout << " OK: " << err_txt << "\n" << " This was expected: " << a.name() << "-data does not fit into char.\n"; e = 0; } a.close(); // Not really necessary since file gets closed automatically // when object 'a' is automatically deteled. return e; } /* Test whether an attemp to read more samples tan available in the file really throws an exception. Returns zero when test succeeded, nonzero when failed. */ int read_too_many_a() { const short max_ch = 4; RDAIFF a; cout << "Test read_too_many_a():\n"; try { a.open("a.aiff"); // 16-bit quadrophonic. if (a.channels() > max_ch) { cout << " Sorry, channels > " << max_ch << "!\n"; return 1; // File gets closed automatically when object a releases. } if (a.frames() != 9) { cout << " Sorry, exactly 9 frames expected!\n"; return 1; } } catch (const char* err_txt) { cout << " " << err_txt << "\n Could not open '" << a.name() << "'!\n"; return 1; // Despite failure, filename is copied into object. } try { signed long long frame[10 * max_ch]; // long long always fits. a.read(frame, 10); // Read more frames than available.. cout << " ERROR: out of data exception expected!\n"; return 1; } catch (const char* err_txt) { cout << " OK: " << err_txt << "\n" << " This was expected: " << a.name() << " contains only " << a.frames() << " frames but 10 were requested.\n"; return 0; } } /* Test whether opening an already opened file really throws an exception. */ int open_open_b() { RDAIFF a; cout << "Test open_open_b():\n"; try { a.open("b.aiff"); } catch (const char* err_txt) { cout << " " << err_txt << "\n Could not open '" << a.name() << "'!\n"; return 1; // Despite failure, filename will be copied. } try { a.open("b.aiff"); cout << " ERROR: opening an open file should throw!\n"; return 1; } catch (const char* err_txt) { cout << " OK: " << err_txt << "\n" << " This was expected: " << a.name() << " already open.\n"; return 0; } } /* Test whether reading a negative amount of frames really throws an exception. */ int read_neg_frames_b() { const short max_ch = 2; RDAIFF a; cout << "Test read_neg_frames_b():\n"; try { a.open("b.aiff"); if (a.channels() > max_ch) { cout << " Sorry, channels > " << max_ch << "!\n"; return 1; } } catch (const char* err_txt) { cout << " " << err_txt << "\n Could not open '" << a.name() << "'!\n"; return 1; // Despite failure, filename will be copied. } try { long long dummy[max_ch * 3]; a.read(dummy, -3); // -3 !! cout << " ERROR: reading negative amount of frames should throw!\n"; return 1; } catch (const char* err_txt) { cout << " OK: " << err_txt << "\n" << " This was expected: number of frames to read was -3.\n"; return 0; } } /* Test peak search in 8-bit file "b.aiff". Demonstrates reading-in to signed characters. Most likely, sizeof(signed char) equals 1 on your computer, meaning this routine can only read 8-bit files (otherwise throws). */ int peaksearch_b() // Find first peak in first channel. { int e = 0; cout << "Test peaksearch_b():\n"; try { const short max_ch = 4; RDAIFF a("b.aiff"); if (a.channels() > max_ch) { cout << " Sorry, channels > " << max_ch << "!\n"; e = 1; } else { long at_frame = -1L; signed char highest = 0; long num_togo = a.frames(); for (long frame = 0; frame < num_togo; frame++) { signed char sample[max_ch]; a.read(sample, 1); // Read only 1 sampleframe per call sample[0] = abs(sample[0]); // (may be more samples per frame). if (sample[0] > highest) // Only inspect the FIRST channel. { highest = sample[0]; at_frame = frame; } } if (highest) { cout << " The (1st of) highest peak(s) in first channel of" << "\n '" << a.name() << "' found at frame " << at_frame << ", abs.val.=" << int(highest) << ": "; if ((at_frame != 37093) || (highest != 115)) { cout << "MISMATCH!\n"; e = 1; } else cout << "OK, this was expected.\n"; } else { cout << " ERROR: file " << a.name() << " is absolutely silent!\n"; e = 1; } } // a.close(); One may forget to call a.close(). } catch (const char* err_txt) // necessary. { cout << " peaksearch_b() failed!\n" << err_txt << endl; e = 1; } return e; } int main() { cout << "Testing RDAIFF C++ utility version 0.16...\n"; int e = contents_a() || // Logic OR (||) makes it stop after first failure. nonfit_a() || // Bitwise OR (|) runs through all tests, always. read_too_many_a() || open_open_b() || read_neg_frames_b() || peaksearch_b(); if (e) cout << "ERROR: RDAIFF test failed!\n\n"; else cout << "Ok, done.\nAll RDAIFF tests passed successfully.\n\n"; return e; }