/* * Modification History * * 2004-August-22 Jason Rohrer * Created. * * 2004-August-31 Jason Rohrer * Added brief fade-in at note start to reduce clicks. * * 2006-October-3 Jason Rohrer * Optimized using profiler. */ #include "MusicNoteWaveTable.h" #include "minorGems/util/SimpleVector.h" #include #include extern double globalShortestNoteLength; extern double globalLongestNoteLength; MusicNote::MusicNote( int inFrequencyIndex, int inLengthIndex, char inReversed ) : mFrequencyIndex( inFrequencyIndex ), mLengthIndex( inLengthIndex ), mReversed( inReversed ) { } MusicNote *MusicNote::copy() { return new MusicNote( mFrequencyIndex, mLengthIndex, mReversed ); } MusicNoteWaveTable::MusicNoteWaveTable( unsigned long inSamplesPerSecond ){ // read frequencies and lengths from files SimpleVector *frequencyVector = new SimpleVector(); SimpleVector *lengthVector = new SimpleVector(); FILE *musicNotePitchesFILE = NULL; FILE *musicNoteLengthsFILE = NULL; if( musicNotePitchesFILE != NULL ) { double readValue; int numRead = 1; while( numRead == 1 ) { numRead = fscanf( musicNotePitchesFILE, "%lf", &readValue ); if( numRead == 1 ) { frequencyVector->push_back( readValue ); } } fclose( musicNotePitchesFILE ); } else { // default pitches // Note N,, means N two octaves down // N'' means two octaves up /* // This one sounds pretty good // but not enough notes, too bland // A,, frequencyVector->push_back( 110 ); // D, frequencyVector->push_back( 146.832 ); // A, frequencyVector->push_back( 220 ); // D frequencyVector->push_back( 293.665 ); // G frequencyVector->push_back( 391.995 ); // C' frequencyVector->push_back( 523.251 ); // E' frequencyVector->push_back( 659.255 ); // G' frequencyVector->push_back( 783.991 ); */ // Instead, use entire two-octaves from c-major scale // Problem: there can be some discords. // However: much more interesting sounding than the two-chord version // above // base note: C, double baseNote = 130.8127827; int majorScaleSteps[7] = {2,2,1,2,2,2,1}; int scaleIndex = 0; int notePower = 0; // two octaves while( notePower < 25 ) { frequencyVector->push_back( baseNote * pow( 2, notePower / 12.0 ) ); notePower += majorScaleSteps[ scaleIndex ]; scaleIndex ++; if( scaleIndex >= 7 ) { // wrap around scaleIndex = 0; } } /* // These are the notes from Transcend level 001 frequencyVector->push_back( 220 ); frequencyVector->push_back( 277.183 ); frequencyVector->push_back( 329.628 ); frequencyVector->push_back( 440 ); frequencyVector->push_back( 554.365 ); frequencyVector->push_back( 659.255 ); */ } if( musicNoteLengthsFILE != NULL ) { double readValue; int numRead = 1; while( numRead == 1 ) { numRead = fscanf( musicNoteLengthsFILE, "%lf", &readValue ); if( numRead == 1 ) { lengthVector->push_back( readValue ); } } fclose( musicNoteLengthsFILE ); } else { // default lengths lengthVector->push_back( globalLongestNoteLength ); lengthVector->push_back( globalShortestNoteLength ); } mFrequencyCount = frequencyVector->size(); mLengthCount = lengthVector->size(); double *frequencies = frequencyVector->getElementArray(); mLengthsInSeconds = lengthVector->getElementArray(); delete frequencyVector; delete lengthVector; mSampleTable = new float**[ mFrequencyCount ]; mSampleCounts = new unsigned long[ mLengthCount ]; for( int F=0; F lengthInSamples ) { numFadeInSamples = lengthInSamples / 2; } // optimizations (found with profiler) // pull these out of inner loop float lengthInSamplesMinusOne = (float)lengthInSamples - 1.0f; float inv_lengthInSamplesMinusOne = 1.0f / lengthInSamplesMinusOne; float *theseSamples = mSampleTable[F][L]; for( unsigned long i=0; imFrequencyIndex, inNote->mLengthIndex, outNumSamples ); }