#include #include //for class ofstream #include //for the sin function #include //for the data types uint32_t, etc. #include //for class numeric_limits #include //for the accumulate alogorithm using namespace std; /* This program automatically creates an output file named sine.wav Move this file sine.wav to your public_html directory, and then point your browser at http://storm.cis.fordham.edu/~jsmith/sine.wav where jsmith is your fordham name. */ int main() { const double half {pow(2.0, 1.0/12.0)}; //half step const double whole {half * half}; //1 whole step = 2 half steps //Convenient names for the values you can put into the pitch field of //each structure in the array of structures. const double C {261.63}; //do: middle C in Hertz const double D {C * whole}; //re const double E {D * whole}; //mi const double F {E * half}; //fa const double G {F * whole}; //sol const double A {G * whole}; //la const double B {A * whole}; //ti const double Chigh {2.0 * C};//do //Sharps and flats, if you need them. //They are the 5 black keys in each octave on the piano. const double Csharp {C * half}; const double Dsharp {D * half}; const double Fsharp {F * half}; const double Gsharp {G * half}; const double Asharp {A * half}; const double Dflat {Csharp}; const double Eflat {Dsharp}; const double Gflat {Fsharp}; const double Aflat {Gsharp}; const double Bflat {Asharp}; struct note { double pitch; //in cycles per second double length; //in seconds }; const note a[] { //Best recollection of Mary had a little lamb {E, .5}, {D, .5}, {C, .5}, {D, .5}, {E, .5}, {E, .5}, {E, 1.0}, {D, .5}, {D, .5}, {D, .5}, {E, .5}, {G, .5}, {G, 1.5}, {E, .5}, {D, .5}, {C, .5}, {D, .5}, {E, .5}, {E, .5}, {E, .5}, {E, .5}, {D, .5}, {D, .5}, {E, .5}, {D, .5}, {C, .5} }; const size_t n {size(a)}; //how many notes //total number of seconds for entire melody double duration {accumulate(begin(a), end(a), 0.0, [](double sum, const note& no) {return sum + no.length;})}; const uint32_t sampleRate {210 * 210}; //in Hertz //Store the sine wave data. //Get a block of memory from the operating system and name it "data". //Treat this block of memory as if it was an array of (short) integers. const int numSamples {static_cast(sampleRate * duration)}; int16_t *const data {new int16_t[numSamples]}; int d {0}; //maximum height of sine wave const int16_t maxheight {numeric_limits::max()}; //Loop through the notes of the melody. for (int i {0}; i < n; ++i) { //Loop through the samples of each note. for (int s {0}; s < sampleRate * a[i].length; ++s) { //Compute the (x, y) coordinates of a point //on the sine wave. const double x {a[i].pitch * 2.0*M_PI * s / sampleRate}; const double y {maxheight * sin(x)}; data[d] = y; ++d; } //Make the last samples of each note gradually fade out. //This lets the next note begin after a brief gap of silence. const int lastSamples {500}; for (int t {min(d, lastSamples)}; t >= 0; --t) { data[d-t-1] *= static_cast(t)/lastSamples; } } //Create a new data type. struct WAVHeader { char chunkId[4]; //Should be "RIFF" uint32_t chunkSize; //Size of the file minus 8 bytes char format[4]; //Should be "WAVE" char subchunk1Id[4]; //Should be "fmt " uint32_t subchunk1Size; //Size of fmt chunk (16 bytes for PCM) uint16_t audioFormat; //1 for PCM (Pulse-Code Modulation) uint16_t numChannels; //Number of channels (1 mono, 2 stereo) uint32_t sampleRate; //Sample rate (e.g., 44100 Hz) uint32_t byteRate; //SampleRate*NumChannels*BitsPerSample/8 uint16_t blockAlign; //NumChannels * BitsPerSample / 8 uint16_t bitsPerSample; //Bits per sample (e.g., 16) char subchunk2Id[4]; //Should be "data" uint32_t subchunk2Size; //Size of the audio data }; //Create one variable of the new data type. WAVHeader header { {'R', 'I', 'F', 'F'}, //chunkId: ResourceInterchangeFileFormat 0, //chunkSize (assigned later) {'W', 'A', 'V', 'E'}, //format {'f', 'm', 't', ' '}, //subchumk1Id 16, //subchunk1Size 1, //audioformat PCM: Pulse-Code Modulation 1, //numchannels sampleRate, //sampleRate: 44100 Hz sampleRate * 1 * 16 / 8,//byteRate 1 * 16 / 8, //blockAlign 16, //bitsPerSample {'d', 'a', 't', 'a'}, //subchunk2Id 0 //subchunk2Size (assiged later) }; //Fill in the two missing fields of the header structure. header.subchunk2Size = numSamples * header.numChannels * header.bitsPerSample / 8; header.chunkSize = 36 + header.subchunk2Size; //Write the header and the data to the binary output file. ofstream file("sine.wav", ios::binary); if (!file) { cerr << "Couln't open output file.\n"; delete[] data; return EXIT_FAILURE; } file.write(reinterpret_cast(&header), sizeof header); file.write(reinterpret_cast(data), header.subchunk2Size); file.close(); delete[] data; return EXIT_SUCCESS; }