attempt at tracker style music
Diff: main.cpp
- Revision:
- 15:209481812170
- Parent:
- 13:8ce494870ba6
--- a/main.cpp Sat Nov 17 16:33:51 2018 +0000 +++ b/main.cpp Thu Feb 07 11:02:56 2019 +0000 @@ -2,62 +2,17 @@ #include "HWSound.h" #include "snd.h" #include "tune.h" +#include "gfx.h" 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; + uint32_t currentSoundSize; int volume; int speed; int repeat; @@ -68,57 +23,78 @@ uint32_t nextBufferIndexToFill = 0; uint32_t nextT = 0; +uint32_t oldBufIndex=0; int currentLine=0; int mytick=0; - +int pattern=0; + +uint32_t myDelay; +uint32_t tempTime; +uint32_t sndTime; + -// note_speed << octave. = speed to play sample +Ticker sounder; +Ticker sounder1; + +bool playMusic = 1; + +const char *noteNames[] = {"--","C ","C#","D ","D#","E ","F ","F#","G ","G#","A ","A#","B "}; -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# - +const int note_speed[]={ +16,17,18,19,20,21,23,24,25,27,29,30, // C, C#, D, D#, E, F, F#, G, G#, A, A#, B, +32,34,36,38,40,43,45,48,51,54,57,60, +64,68,72,76,81,85,91,96,102,108,114,121, +128,136,144,152,161,171,181,192,203,215,228,242, +256,271,287,304,323,342,362,384,406,431,456,483, +512,542,575,609,645,683,724,767,813,861,912,967, +1024,1085,1149,1218,1290,1367,1448,1534,1625,1722,1825,1933, +2048,2170,2299,2435,2580,2734,2896,3068,3251,3444,3649,3866, +4096,4339,4598,4871,5161,5467,5793,6137,6502,6889,7298,7732,}; -void emptyBuffer(){ - for(int t=0; t<SBUFSIZE;){ - soundbuf[++t]=0; +// new playsound function +uint8_t playSound(int channel, const unsigned char *sound, int volume = 255, int speed=255, int repeat=0){ + + // get sound length + int soundSize = 0; + for(int t=0; t<4; t++){ + soundSize <<= 8; + soundSize |= sound[t] & 0xFF; } - for(int t=0; t<4; t++){ - snd[t].playSample=0; + int sampleRate = 0; + for(int t=0; t<2; t++){ + sampleRate <<= 8; + sampleRate |= sound[t+4] & 0xFF; } + float spd = (POK_AUD_FREQ / (float)sampleRate); + + snd[channel].currentSound = sound; // sound to play + snd[channel].volume = volume; // volume + snd[channel].speed = (speed/spd); // recalculated above + snd[channel].currentSoundSize = soundSize; // length of sound array adjusted for speed change + snd[channel].soundPoint = 0; // where the current sound is upto + snd[channel].repeat = repeat; // repeat point + snd[channel].playSample = 1; // trigger sample playing + + return channel; + } -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; - - return channel; -} uint8_t mixSound(int samplePos) { int temp = 0; - int ss[4]; - + signed 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){ + int currentPos = (snd[s].soundPoint*snd[s].speed)>>8; + ss[s] = snd[s].currentSound[currentPos] -127; + ss[s] *= snd[s].volume; + ss[s] /= 256; + ss[s] *= snd[s].playSample; // will be 1 or 0, if not playing, will silence + snd[s].soundPoint++; + if( currentPos >= snd[s].currentSoundSize){ if(snd[s].repeat){ snd[s].soundPoint=0; }else{ @@ -126,91 +102,108 @@ snd[s].soundPoint=0; } } - } - - -// 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; - - 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; - - 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}; - - if(oldQuart != quart){ - oldQuart = quart; - 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++; - } - } - + } + temp = (ss[0] + ss[1] + ss[2] + ss[3])/4; + return temp +127; } void update_tune(){ - 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; - - if(note > 0){ - - int speed = (note_speed[note-1] << octave); // >> 1 + if(playMusic==1){ + + char pat = my_pattern[pattern]; + + int special = 0; + for(int t=0; t<4; t++){ + 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]; + special = tune[pat][currentLine][t][4]; + + if(special == 22){ + // 22 = F in MOD format. 0.02 = 1 'tick' + sounder.detach(); + sounder.attach(&update_tune, 0.02 * tune[pat][currentLine][t][5]); // speed of song + } + + + // if valid volume change, change it, if not use previous + if(volume >=128){ + volume -=128; + volume *= 4; + }else{ + // don't change volume + volume = snd[t].volume; + } + - switch(instrument){ - case 1: - playSound(t, s_01, sizeof(s_01), volume, speed, sampleRepeat[0]); - break; - case 2: - playSound(t, s_02, sizeof(s_02), volume, speed, sampleRepeat[1]); - break; - case 3: - playSound(t, s_03, sizeof(s_03), volume, speed, sampleRepeat[2]); - break; - case 4: - playSound(t, s_04, sizeof(s_04), volume, speed, sampleRepeat[3]); - break; + if(note > 0){ + + //int speed = (note_speed[note-1] << octave) /2; + int speed = note_speed[note-1]; + for(int s=1; s<octave; s++){ + speed *=2; + } + + switch(instrument){ + case 1: playSound(t, s_01, volume, speed, sampleRepeat[instrument-1]); break; + case 2: playSound(t, s_02, volume, speed, sampleRepeat[instrument-1]); break; + case 3: playSound(t, s_03, volume, speed, sampleRepeat[instrument-1]); break; + case 4: playSound(t, s_04, volume, speed, sampleRepeat[instrument-1]); break; + case 5: playSound(t, s_05, volume, speed, sampleRepeat[instrument-1]); break; + case 6: playSound(t, s_06, volume, speed, sampleRepeat[instrument-1]); break; + case 7: playSound(t, s_07, volume, speed, sampleRepeat[instrument-1]); break; + case 8: playSound(t, s_08, volume, speed, sampleRepeat[instrument-1]); break; + case 9: playSound(t, s_09, volume, speed, sampleRepeat[instrument-1]); break; + case 10: playSound(t, s_10, volume, speed, sampleRepeat[instrument-1]); break; + case 11: playSound(t, s_11, volume, speed, sampleRepeat[instrument-1]); break; + case 12: playSound(t, s_12, volume, speed, sampleRepeat[instrument-1]); break; + case 13: playSound(t, s_13, volume, speed, sampleRepeat[instrument-1]); break; + } } + + snd[t].volume = volume; + } - - snd[t].volume = volume; - + + // patterns are 64 lines long, or until special code 20. + if(currentLine++==63 || special == 20){ + currentLine=0; + if(++pattern>=sizeof(my_pattern))pattern=0; + } + + } // playMusic +} + + +int beatCounter; +void update_buffer(){ + + int quart = soundbufindex / 512; + int sndOffset[]={1024,1536,0,512}; + + if(oldQuart != quart){ + oldQuart = quart; + for(int t=0; t<=SBUFSIZE/4;){ + uint8_t sample = mixSound(t); + soundbuf[t+sndOffset[quart]] = sample; + t++; + } +// if(beatCounter++==3){ +// beatCounter=0; +// update_tune(); +// } } - - if(currentLine++==63){ - currentLine=0; - pattern++; + +} + +// print text +void print(uint16_t x, uint16_t y, const char* text){ + for(uint8_t t = 0; t < strlen(text); t++){ + uint8_t character = text[t]; + d.drawBitmap(x,y,tinyfont[character]); + x += 4; } } @@ -218,58 +211,72 @@ 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; + mygame.setFrameRate(255); // Init audio stream. pokPlayStream(); // activate stream mygame.sound.ampEnable(true); mygame.sound.playMusicStream(); - - - uint32_t nextBufferIndexToFill = 0; + + sounder.attach(&update_tune, 0.08); // speed of song + + + d.load565Palette(&tinyfont_pal[0]); 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(); - } - + update_buffer(); + if (mygame.update()) { - // update buttons - myPad = updateButtons(myPad); - UpdatePad(myPad); - d.color = 1; - d.printf("Tick %d", mytick); - d.printf("Line %d", currentLine); + //d.printf("Pattern %d\n", pattern); + //d.printf("Line %d\n", currentLine); + + char pat = my_pattern[pattern]; + + char tempText[20]; + + int s1=currentLine-5; + if(s1<0)s1=0; + int s2 = currentLine+5; + if(s2>63)s2=63; + + sprintf(tempText,"T[%2d] P[%2d] L[%2d]",pattern,pat,currentLine); + print(0,0,tempText); + + int s; + for(s=s1; s<s2; s++){ + + for(int t=0; t<4; t++){ + int note = tune[pat][s][t][0]; + int octave = tune[pat][s][t][1]; // no longer used + int volume = tune[pat][s][t][2];// max volume from xm/mod was 64 + int instrument = tune[pat][s][t][3]; + int special = tune[pat][s][t][4]; + + if(volume >=128){ + volume -=128; + } + + int x1 = t*27; + int y1 = ((8-currentLine)+s)*6; + + if(s == currentLine || s == currentLine+1){ + d.setColor(5); + d.drawLine(0, y1-1, 219, y1-1); + } + + print(x1,y1,noteNames[note]); + sprintf(tempText,"%d",octave); + print(x1 + 8,y1,tempText); + sprintf(tempText,"%d",volume); + print(x1 + 12,y1,tempText); + sprintf(tempText,"%2d|",instrument); + print(x1 + 16,y1,tempText); + + } + } } }