/* RDAIFFPP version 0.16, december 30, 2019, a C++ class to read AIFF files. Latest version at: https://ecomaan.nl/cpp/rdaiffpp Example program that reads-in the 2 provided test-files, a.aiff and b.aiff. With the RDAIFF class you cannot read raw bytes from an AIFF file. You cannot even distract single-channel samples from a multichannel file. RDAIFF is a high-level interface and the minimum you can read from a file is ONE (channel-interleaved) sampleframe (depending on the AIFF header how many samples, i.e. channels that is). In the examples below, single frames are read in, which is nice for simplicity and as example-code. It is not efficient however, and you 'd better read in larger amounts per call to RDAIFF::read(). */ #include #include // To format/layout output. #include // For abs(). using namespace std; #include "rdaiff.hpp" static void dump_head(short num_channels) { cout << " frame: "; for (short ch = 0; ch < num_channels; ch++) cout << "channel" << ch << ": "; cout << endl; } /* Demonstrates reading in to floats and into shorts, dumping all samples to the standard output. Shows the use of rewind() and two different ways of reading in a complete AIFF file. */ static void dump_frames(const char* filename) { try { short ch; const short max_ch = 16; RDAIFF a(filename); // Try to open an existing AIFF file. // String is copied in RDAIFF object. a.info(cout); // Print file statistics to stdout. if (a.channels() > max_ch) cout << " Sorry, channels > " << max_ch << ", please recompile.\n"; else { cout << " All " << a.frames() << " sampleframes in file '" << a.name() << "' converted to floats:\n"; dump_head(a.channels()); for (long long frame = 0; frame < a.frames(); frame++) { float fl_sample[max_ch]; // Double yields the same: -1 to +1. a.read(fl_sample, 1); // Read 1 frame per call (for simplicity). cout << right << setw(5) << frame << ": " << left; for (ch = 0; ch < a.channels(); ch++) cout << setw(12) << fl_sample[ch] << ' '; cout << endl; } // No need to close and re-open. a.rewind(); // Makes frames_togo() = frames() again. cout << " The same " << a.frames_togo() << " frames, read into shorts:\n"; dump_head(a.channels()); while (a.frames_togo()) // Another way of looping, using { // the internal frame-counter. short sh_frame[max_ch]; // One single sampleframe. cout << right << setw(5) << a.frames()-a.frames_togo() << ":"; a.read(sh_frame, 1); // Reading more than 1 frame per read()- // call would be much more efficient. for (ch = 0; ch < a.channels(); ch++) cout << setw(11) << sh_frame[ch] << " "; cout << endl; } } cout << endl; // Always good to close explicitly after use, but when a.close(); // you forget this, the destructor will call close() for } // you (here, the destructor gets called automatically). catch (const char* err_txt) { cout << "\n dump_frames(" << filename << ") failed!\n" << err_txt << endl; } } /* Demonstrates reading-in to signed characters. Most likely, sizeof(signed char) equals 1 on your computer, meaning this routine can only process 8-bit files. Finds and reports the (first of) highest peak(s) in the first channel. */ static void find_peak(const char* filename) // Find first peak in first channel. { try { const short max_ch = 4; RDAIFF* a = new RDAIFF(filename); // Dynamic object allocation. // String is copied in RDAIFF obj. a->info(cout); // Print AIFF hdr info to stdout. if (a->channels() > max_ch) cout << " Sorry, channels > " << max_ch << ", please recompile.\n"; else { long at_frame = -1L; signed char highest = 0; long long num_togo = a->frames(); for (long 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 " << at_frame / a->samplerate() << " seconds (abs.val.=" << float(highest) / 1.28 << "%)."; else cout << "File " << a->name() << " is absolutely silent."; } cout << endl << endl; a->close(); // Sane habit but one may forget to call a->close(). delete a; // But never forget to delete (when you used 'new')! } // RDAIFF destructor will call a->close() automatically if necessary. catch (const char* err_txt) { cout << "\n find_peak(" << filename << ") failed!\n" << err_txt << endl; } } int main() { cout << "Demonstrating RDAIFF C++ utility version 0.16.\n\n"; // Input files are expected in current directory. dump_frames("a.aiff"); // Example file with only seven 4-channel frames. find_peak ("b.aiff"); // Longer example file with synthetic bells. return 0; }