/* WRAIFFPP 0.26 (december 30, 2019), a tiny audiofile writing utility in C++. Latest version at: https://ecomaan.nl/cpp/wraiffpp Demonstrates the creation of AIFF files using the WRAIFFPP utility. */ #include // For sin(). #include // To construct filenames in a stringstream. #include #include // For cout and ostream. #include // For rand(). using namespace std; #include "wraiff.hpp" // Also add wraiff.cpp in your C++ project or makefile. // Demonstrates writing of shorts to a 16-bit mono file. Uses dynamic WRAIFF // object allocation (new) and deletion (delete). Writes white noise at 48 KHz. int mono_noise() { try { const double sr = 48000.0; WRAIFF* a = new WRAIFF("white_mono.aiff", // Filename. sr, // Samplerate in Hz. 1, // Monophonic. 16); // 16 bits per sample. for (long n = 0; n < static_cast(sr); n++) // For one second. { short sample = (rand() & 32767) - 16384; // At -6 dB. a->write(&sample, 1); // Although not too efficient, } // only one sampleframe per call. a->info(cout); // Print file statistics to standard output. /* a->close(); File will be closed automatically by the destructor but it is better to close it yourself. */ delete a; // Explicitly call the destructor (rewrites return 0; // the AIFF header and closes the file). } catch (const char* err_txt) { cout << err_txt; // When something goes wrong, the WRAIFF utility return 1; // throws an exception (describing the error). } } // Demonstrates writing of signed characters to an 8-bit stereo file, using a // stereo-interleaved buffer (256 frames) and automatic WRAIFF object deletion. int stereo_noise() { try { const int ch = 2; // Number of channels. const double sr = 22050.0; // Samplerate in cycles per second. WRAIFF a("white_stereo.aiff", // C-string gets copied into WRAIFF object. sr, // Number of samples per second (Hertz). ch, // Number of channels (between 1 and 128). 8); // Number of bits per channel (8, 16 or 24). const int buff_frames = 256; signed char sample[ch * buff_frames]; long togo = static_cast(0.5+(sr*2.34)); // For 2.34 seconds. long f; while (togo) { if (togo > buff_frames) f = buff_frames; else f = togo; // White noise at 0 dB for (short b = 0; b < f * ch; b++) // on all channels. sample[b] = static_cast((rand() & 255) - 128); a.write(sample, f); togo -= f; } a.info(cout); // Print file statistics to the standard output. /* a.close(); File will be closed automatically by the destructor but it is better to close it yourself. */ return 0; // It would be wrong to call a destructor here. } catch (const char* err_txt) { cout << err_txt; // When something goes wrong, the WRAIFF utility return 1; // throws an exception (describing the error). } } // Demonstrates writing of doubles to 24-bit mono, stereo, and quadrophonic // files. The latter 2 use interleaved channel data. Explicitly calling open() // and close(); variable 'a' refers to 3 different files, 'a' is thus re-used. int three_files() // Generate 3 audiofiles. { WRAIFF a; const double samplerate = 44100.0; const short max_chan = 4; // Interleaved audiobuffer (containing double s[max_chan]; // just 1 single frame for simplicity). for (short ch = 1; ch <= max_chan; ch <<= 1) // Mono, stereo, quadrophonic. { ostringstream fname(""); // Construct new filename. fname << ch << "-channel.aiff"; try { a.open(fname.str().c_str(), // C-string gets copied into WRAIFF object. samplerate, // Number of samples per second (Hertz). ch, // Number of channels (between 1 and 128). 24); // Number of bits per channel (8, 16 or 24). } catch (const char* err_txt) { cout << err_txt << "Cannot create/overwrite '" << fname.str() << "'!\n"; return 1; } // Play 'ch' sinewaves for 0.75 seconds. for (long n = 0; n < static_cast(0.5 + (0.75 * samplerate)); n++) { // First channel at (0.1 samplerate)/(2 PI) Hz. double f = 0.1; for (short c = 0; c < ch; c++) { s[c] = 0.25 * sin(f * static_cast(n)); // 0.25 --> -12 dB. f *= 1.2; // Stack natural minor thirds (5:6), at 44k1: } // 701.87 Hz; 842.25 Hz; 1010.70 Hz; 1212.84 Hz. try { // Only one frame in the buffer thus call with 1. a.write(s, 1); // But notice it is more efficient to call write() } // with a higher number of frames (and larger s[]). catch (const char* err_txt) { cout << err_txt; break; // Close file as soon as an error (or clip) occurs. } } a.info(cout); // Print file statistics to stdout (may throw). try { a.close(); // Rewrite AIFF header and close the file. } catch (const char* err_txt) { cout << err_txt << "Error closing '" << fname.str() << "'!\n"; return 1; } } return 0; } int main() { cout << "Demonstrating the WRAIFF C++ utility (v0.25).\n"; if (mono_noise() || // Create a 16-bit file containing white noise. stereo_noise() || // Create an 8-bit file containing white noise. three_files()) // And 3 files containing pure sinewaves. return 1; cout << "Ok, done.\n"; return 0; // Return 0 or 1 to the operating system. }