attempt at tracker style music
Diff: main.cpp
- Revision:
- 14:97a5deea7c94
- Parent:
- 13:8ce494870ba6
--- a/main.cpp Sat Nov 17 16:33:51 2018 +0000 +++ b/main.cpp Sun Nov 25 08:58:30 2018 +0000 @@ -6,106 +6,56 @@ Pokitto::Core mygame; Pokitto::Display d; -//------------------------[ Button handling, very accurate ]------------------------ -#define HELD 0 -#define NEW 1 -#define RELEASE 2 -byte CompletePad, ExPad, TempPad, myPad; -bool _A[3], _B[3], _C[3], _Up[3], _Down[3], _Left[3], _Right[3]; - -DigitalIn _aPin(P1_9); -DigitalIn _bPin(P1_4); -DigitalIn _cPin(P1_10); -DigitalIn _upPin(P1_13); -DigitalIn _downPin(P1_3); -DigitalIn _leftPin(P1_25); -DigitalIn _rightPin(P1_7); - -void UPDATEPAD(int pad, int var) { - _C[pad] = (var >> 1)&1; - _B[pad] = (var >> 2)&1; - _A[pad] = (var >> 3)&1; - _Down[pad] = (var >> 4)&1; - _Left[pad] = (var >> 5)&1; - _Right[pad] = (var >> 6)&1; - _Up[pad] = (var >> 7)&1; -} - -void UpdatePad(int joy_code){ - ExPad = CompletePad; - CompletePad = joy_code; - UPDATEPAD(HELD, CompletePad); // held - UPDATEPAD(RELEASE, (ExPad & (~CompletePad))); // released - UPDATEPAD(NEW, (CompletePad & (~ExPad))); // newpress -} - -byte updateButtons(byte var){ - var = 0; - if (_cPin) var |= (1<<1); - if (_bPin) var |= (1<<2); - if (_aPin) var |= (1<<3); // P1_9 = A - if (_downPin) var |= (1<<4); - if (_leftPin) var |= (1<<5); - if (_rightPin) var |= (1<<6); - if (_upPin) var |= (1<<7); - - return var; -} - - typedef struct{ - bool playSample; - int soundPoint; - const uint8_t *currentSound; - int currentSoundSize; - int volume; - int speed; - int repeat; + bool playSample; // should this sound be playing now? + int soundPoint; // current position of sound + const uint8_t *currentSound; // currend sound array playing + uint32_t currentSoundSize; // length of current sound + int volume; // volume of sound, best to be 63 or lower + int speed; // how fast to play sound, 256 = 100% + bool repeat; // 1 to repeat 0 not to + int repeat_start; // start point of repeat, default should be 0 + int repeat_end; // end point of repeate, default should be currentSoundSize + char lastSample; // previous sample played } sampletype; -sampletype snd[4]; // up to 4 sounds at once? +sampletype snd[4]; // up to 4 sounds at once? int oldQuart; -uint32_t nextBufferIndexToFill = 0; -uint32_t nextT = 0; - int currentLine=0; int mytick=0; - - -// note_speed << octave. = speed to play sample - -int note_speed[]={ 27,30,16,18,20,21,24, 29,0 ,17,19,0 ,23,25}; -// A B C D E F G A# B# C# D# E# F# G# - +int pattern=0; -void emptyBuffer(){ - for(int t=0; t<SBUFSIZE;){ - soundbuf[++t]=0; - } - - for(int t=0; t<4; t++){ - snd[t].playSample=0; - } +Ticker soundPlay; +Ticker musicTimer; -} +const float note_speed[]={ +// C, C#, D, D#, E, F, F#, G, G#, A, A#, B, +16.00, 16.95, 17.96, 19.03, 20.16, 21.36, 22.62, 23.97, 25.40, 26.91, 28.51, 30.21, +32.00, 33.90, 35.92, 38.05, 40.31, 42.71, 45.25, 47.95, 50.79, 53.82, 57.02, 60.41, +64.00, 67.81, 71.84, 76.11, 80.64, 85.43, 90.51, 95.89, 101.60, 107.63, 114.03, 120.81, +128.00, 135.61, 143.67, 152.21, 161.26, 170.85, 181.02, 191.78, 203.18, 215.27, 228.06, 241.63, +256.00, 271.22, 287.34, 304.43, 322.54, 341.71, 362.03, 383.56, 406.36, 430.53, 456.13, 483.25, +511.99, 542.44, 574.69, 608.86, 645.06, 683.43, 724.07, 767.12, 812.74, 861.06, 912.27, 966.51, +1023.98, 1084.87, 1149.38, 1217.73, 1290.14, 1366.85, 1448.13, 1534.24, 1625.47, 1722.13, 1824.53, 1933.02, +2047.96, 2169.74, 2298.77, 2435.46, 2580.27, 2733.71, 2896.26, 3068.48, 3250.94, 3444.25, 3649.06, 3866.05, +4095.93, 4339.49, 4597.52, 4870.91, 5160.55, 5467.41, 5792.52, 6136.96, 6501.89, 6888.51, 7298.12, 7732.08 +}; -uint8_t playSound(int channel, const unsigned char *sound, uint16_t soundSize, int volume = 255, int speed=255, int repeat=0){ -/* - int channel=0; - for(int t=0; t<4; t++){ - if(snd[t].playSample==0){ - channel=t; - } - } -*/ - snd[channel].currentSound = sound; - snd[channel].currentSoundSize = (soundSize*255)/speed; - snd[channel].soundPoint = 0; - snd[channel].playSample = 1; - snd[channel].volume = volume; - snd[channel].speed = speed; - snd[channel].repeat = repeat; +uint8_t playSound(int channel, const unsigned char *sound, uint32_t soundSize, int volume = 255, int speed=255, int repeat=0){ + + // to resample current sample rate to 44100, cheap and probably wrong way + float rate1 = 44100 / (float)sampleRates[channel]; + // speed = 256 / rate1; // playback speed is + speed = speed / rate1; // playback speed is + + snd[channel].currentSound = sound; // sound to play + snd[channel].currentSoundSize = (soundSize<<8)/speed; // length of sound array adjusted for speed change + snd[channel].volume = 63; // volume, best kept below 64 as louder will cause clipping when playing multiple samples + snd[channel].speed = speed; // recalculated above + snd[channel].repeat = repeat; // 1 to repead, 0 to not + snd[channel].soundPoint = 0; // where the current sound is upto + snd[channel].playSample = 1; // 1 to play this sound, 0 not to return channel; } @@ -116,7 +66,9 @@ int ss[4]; for(int s=0; s<4; s++){ + ss[s] = (snd[s].currentSound[(snd[s].soundPoint*snd[s].speed)>>8]*snd[s].volume>>8) * snd[s].playSample; + ++snd[s].soundPoint; if(snd[s].soundPoint >= snd[s].currentSoundSize){ if(snd[s].repeat){ @@ -128,66 +80,43 @@ } } - -// temp = (ss[0] + ss[1] + ss[2] + ss[3]) - (ss[0] * ss[1] * ss[2] * ss[3]); - temp = ((127 - ss[0] + ss[1] + ss[2] + ss[3])/4)+127; + temp = (ss[0] + ss[1] + ss[2] + ss[3]) - ((ss[0] * ss[1] * ss[2] * ss[3])/256); return temp; } -// Fills an audio buffer with the samples generated by the Bytebeat function -void generateBuffer(uint32_t bufferIndex, uint32_t nextT) { - - //bufferIndex = (currentBuffer + 2)&3; + +void updateAudioBuffer(){ + // when updating the audio buffer, I split the buffer into 4 and fill + // a part that isn't being played, so there are no sync issues - uint32_t index= 0; - for(uint32_t t=0; t<BUFFER_SIZE; t++,index++){ - uint8_t sample = mixSound(t); - buffers[bufferIndex][index] = sample; - } - -} - - -void updateSample(){ - - int quart = soundbufindex / 512; - int sndOffset[]={512,1024,1536,0}; - + int quart = soundbufindex / 512; + int sndOffset[]={1024,1536,0,512}; + + // only update if the current playback pointer is nowhere near where we want to fill if(oldQuart != quart){ oldQuart = quart; - for(int t=0; t<SBUFSIZE/4;){ + for(int t=0; t<=SBUFSIZE/4;){ uint8_t sample = mixSound(t); soundbuf[t+sndOffset[quart]] = sample; - - for(int s=0; s<4; s++){ - ++snd[s].soundPoint; - if(snd[s].soundPoint >= snd[s].currentSoundSize){ - if(snd[s].repeat){ - snd[s].soundPoint=0; - }else{ - snd[s].playSample=0; - } - } - } t++; } } - } void update_tune(){ + char pat = my_pattern[pattern]; + for(int t=0; t<4; t++){ - char note = tune[pattern][currentLine][t][0]; - char octave = tune[pattern][currentLine][t][1]; - char instrument = tune[pattern][currentLine][t][2]; - char volume = tune[pattern][currentLine][t][3] * 4; + int note = tune[pat][currentLine][t][0]; + int octave = tune[pat][currentLine][t][1]; // no longer used + int volume = tune[pat][currentLine][t][2];// max volume from xm/mod was 64 + int instrument = tune[pat][currentLine][t][3]; if(note > 0){ - - int speed = (note_speed[note-1] << octave); // >> 1 - + int speed = note_speed[(note-1)+12*octave]; + switch(instrument){ case 1: playSound(t, s_01, sizeof(s_01), volume, speed, sampleRepeat[0]); @@ -202,75 +131,43 @@ playSound(t, s_04, sizeof(s_04), volume, speed, sampleRepeat[3]); break; } + } - - snd[t].volume = volume; - + if(volume >= 128){ + snd[t].volume = volume-128; + } } - if(currentLine++==63){ + if(currentLine++==patternLength){ currentLine=0; - pattern++; + if(pattern++==sizeof(my_pattern))pattern=loopTo; } } + + int main () { mygame.begin(); mygame.setFrameRate(255); -// emptyBuffer(); // clear the sound buffer - - // The audio engine uses 4 buffers. Generate all 4 buffers ahead. - uint32_t nextT = 0; - generateBuffer(0, nextT); nextT += BUFFER_SIZE; - generateBuffer(1, nextT); nextT += BUFFER_SIZE; - generateBuffer(2, nextT); nextT += BUFFER_SIZE; - generateBuffer(3, nextT); nextT += BUFFER_SIZE; - - // Set global audio variables - currentBuffer = 0; - currentPtr = buffers[currentBuffer]; - endPtr = currentPtr + BUFFER_SIZE; // Init audio stream. pokPlayStream(); // activate stream mygame.sound.ampEnable(true); mygame.sound.playMusicStream(); - + + // check and update the sound buffer as often as we can + soundPlay.attach(&updateAudioBuffer, 0.0001); + musicTimer.attach(&update_tune, 0.055); - uint32_t nextBufferIndexToFill = 0; + d.color = 1; while (mygame.isRunning()) { -// updateSample(); - - // Fill the next buffer if it is not used currently - if((uint32_t)currentBuffer != nextBufferIndexToFill) { - // Generate buffer - generateBuffer(nextBufferIndexToFill, nextT); - - if(++nextBufferIndexToFill > 3) - nextBufferIndexToFill = 0; - nextT += BUFFER_SIZE; - } - - if(++mytick==2){ - mytick=0; - - update_tune(); - } - if (mygame.update()) { - // update buttons - myPad = updateButtons(myPad); - UpdatePad(myPad); - - d.color = 1; - d.printf("Tick %d", mytick); - d.printf("Line %d", currentLine); - + } } }