attempt at tracker style music
main.cpp
- Committer:
- spinal
- Date:
- 2018-11-25
- Revision:
- 14:97a5deea7c94
- Parent:
- 13:8ce494870ba6
File content as of revision 14:97a5deea7c94:
#include "Pokitto.h" #include "HWSound.h" #include "snd.h" #include "tune.h" Pokitto::Core mygame; Pokitto::Display d; typedef struct{ 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? int oldQuart; int currentLine=0; int mytick=0; int pattern=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, 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; } uint8_t mixSound(int samplePos) { int temp = 0; 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){ snd[s].soundPoint=0; }else{ snd[s].playSample=0; snd[s].soundPoint=0; } } } temp = (ss[0] + ss[1] + ss[2] + ss[3]) - ((ss[0] * ss[1] * ss[2] * ss[3])/256); return temp; } 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 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;){ uint8_t sample = mixSound(t); soundbuf[t+sndOffset[quart]] = sample; t++; } } } void update_tune(){ char pat = my_pattern[pattern]; 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]; if(note > 0){ int speed = note_speed[(note-1)+12*octave]; 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(volume >= 128){ snd[t].volume = volume-128; } } if(currentLine++==patternLength){ currentLine=0; if(pattern++==sizeof(my_pattern))pattern=loopTo; } } int main () { mygame.begin(); mygame.setFrameRate(255); // 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); d.color = 1; while (mygame.isRunning()) { if (mygame.update()) { } } }