attempt at tracker style music
main.cpp@14:97a5deea7c94, 2018-11-25 (annotated)
- Committer:
- spinal
- Date:
- Sun Nov 25 08:58:30 2018 +0000
- Revision:
- 14:97a5deea7c94
- Parent:
- 13:8ce494870ba6
A program to play music on pokitto
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Pokitto | 0:2d2a3994d55d | 1 | #include "Pokitto.h" |
spinal | 13:8ce494870ba6 | 2 | #include "HWSound.h" |
spinal | 13:8ce494870ba6 | 3 | #include "snd.h" |
spinal | 13:8ce494870ba6 | 4 | #include "tune.h" |
Pokitto | 0:2d2a3994d55d | 5 | |
Pokitto | 0:2d2a3994d55d | 6 | Pokitto::Core mygame; |
spinal | 12:37d999e445ad | 7 | Pokitto::Display d; |
Pokitto | 0:2d2a3994d55d | 8 | |
spinal | 13:8ce494870ba6 | 9 | typedef struct{ |
spinal | 14:97a5deea7c94 | 10 | bool playSample; // should this sound be playing now? |
spinal | 14:97a5deea7c94 | 11 | int soundPoint; // current position of sound |
spinal | 14:97a5deea7c94 | 12 | const uint8_t *currentSound; // currend sound array playing |
spinal | 14:97a5deea7c94 | 13 | uint32_t currentSoundSize; // length of current sound |
spinal | 14:97a5deea7c94 | 14 | int volume; // volume of sound, best to be 63 or lower |
spinal | 14:97a5deea7c94 | 15 | int speed; // how fast to play sound, 256 = 100% |
spinal | 14:97a5deea7c94 | 16 | bool repeat; // 1 to repeat 0 not to |
spinal | 14:97a5deea7c94 | 17 | int repeat_start; // start point of repeat, default should be 0 |
spinal | 14:97a5deea7c94 | 18 | int repeat_end; // end point of repeate, default should be currentSoundSize |
spinal | 14:97a5deea7c94 | 19 | char lastSample; // previous sample played |
spinal | 13:8ce494870ba6 | 20 | } sampletype; |
spinal | 13:8ce494870ba6 | 21 | |
spinal | 14:97a5deea7c94 | 22 | sampletype snd[4]; // up to 4 sounds at once? |
spinal | 13:8ce494870ba6 | 23 | int oldQuart; |
spinal | 13:8ce494870ba6 | 24 | |
spinal | 13:8ce494870ba6 | 25 | int currentLine=0; |
spinal | 13:8ce494870ba6 | 26 | int mytick=0; |
spinal | 14:97a5deea7c94 | 27 | int pattern=0; |
spinal | 11:a573cacdc078 | 28 | |
spinal | 14:97a5deea7c94 | 29 | Ticker soundPlay; |
spinal | 14:97a5deea7c94 | 30 | Ticker musicTimer; |
spinal | 13:8ce494870ba6 | 31 | |
spinal | 14:97a5deea7c94 | 32 | const float note_speed[]={ |
spinal | 14:97a5deea7c94 | 33 | // C, C#, D, D#, E, F, F#, G, G#, A, A#, B, |
spinal | 14:97a5deea7c94 | 34 | 16.00, 16.95, 17.96, 19.03, 20.16, 21.36, 22.62, 23.97, 25.40, 26.91, 28.51, 30.21, |
spinal | 14:97a5deea7c94 | 35 | 32.00, 33.90, 35.92, 38.05, 40.31, 42.71, 45.25, 47.95, 50.79, 53.82, 57.02, 60.41, |
spinal | 14:97a5deea7c94 | 36 | 64.00, 67.81, 71.84, 76.11, 80.64, 85.43, 90.51, 95.89, 101.60, 107.63, 114.03, 120.81, |
spinal | 14:97a5deea7c94 | 37 | 128.00, 135.61, 143.67, 152.21, 161.26, 170.85, 181.02, 191.78, 203.18, 215.27, 228.06, 241.63, |
spinal | 14:97a5deea7c94 | 38 | 256.00, 271.22, 287.34, 304.43, 322.54, 341.71, 362.03, 383.56, 406.36, 430.53, 456.13, 483.25, |
spinal | 14:97a5deea7c94 | 39 | 511.99, 542.44, 574.69, 608.86, 645.06, 683.43, 724.07, 767.12, 812.74, 861.06, 912.27, 966.51, |
spinal | 14:97a5deea7c94 | 40 | 1023.98, 1084.87, 1149.38, 1217.73, 1290.14, 1366.85, 1448.13, 1534.24, 1625.47, 1722.13, 1824.53, 1933.02, |
spinal | 14:97a5deea7c94 | 41 | 2047.96, 2169.74, 2298.77, 2435.46, 2580.27, 2733.71, 2896.26, 3068.48, 3250.94, 3444.25, 3649.06, 3866.05, |
spinal | 14:97a5deea7c94 | 42 | 4095.93, 4339.49, 4597.52, 4870.91, 5160.55, 5467.41, 5792.52, 6136.96, 6501.89, 6888.51, 7298.12, 7732.08 |
spinal | 14:97a5deea7c94 | 43 | }; |
spinal | 13:8ce494870ba6 | 44 | |
spinal | 14:97a5deea7c94 | 45 | uint8_t playSound(int channel, const unsigned char *sound, uint32_t soundSize, int volume = 255, int speed=255, int repeat=0){ |
spinal | 14:97a5deea7c94 | 46 | |
spinal | 14:97a5deea7c94 | 47 | // to resample current sample rate to 44100, cheap and probably wrong way |
spinal | 14:97a5deea7c94 | 48 | float rate1 = 44100 / (float)sampleRates[channel]; |
spinal | 14:97a5deea7c94 | 49 | // speed = 256 / rate1; // playback speed is |
spinal | 14:97a5deea7c94 | 50 | speed = speed / rate1; // playback speed is |
spinal | 14:97a5deea7c94 | 51 | |
spinal | 14:97a5deea7c94 | 52 | snd[channel].currentSound = sound; // sound to play |
spinal | 14:97a5deea7c94 | 53 | snd[channel].currentSoundSize = (soundSize<<8)/speed; // length of sound array adjusted for speed change |
spinal | 14:97a5deea7c94 | 54 | snd[channel].volume = 63; // volume, best kept below 64 as louder will cause clipping when playing multiple samples |
spinal | 14:97a5deea7c94 | 55 | snd[channel].speed = speed; // recalculated above |
spinal | 14:97a5deea7c94 | 56 | snd[channel].repeat = repeat; // 1 to repead, 0 to not |
spinal | 14:97a5deea7c94 | 57 | snd[channel].soundPoint = 0; // where the current sound is upto |
spinal | 14:97a5deea7c94 | 58 | snd[channel].playSample = 1; // 1 to play this sound, 0 not to |
spinal | 12:37d999e445ad | 59 | |
spinal | 13:8ce494870ba6 | 60 | return channel; |
spinal | 13:8ce494870ba6 | 61 | } |
spinal | 13:8ce494870ba6 | 62 | |
spinal | 13:8ce494870ba6 | 63 | uint8_t mixSound(int samplePos) |
spinal | 13:8ce494870ba6 | 64 | { |
spinal | 13:8ce494870ba6 | 65 | int temp = 0; |
spinal | 13:8ce494870ba6 | 66 | int ss[4]; |
spinal | 12:37d999e445ad | 67 | |
spinal | 13:8ce494870ba6 | 68 | for(int s=0; s<4; s++){ |
spinal | 14:97a5deea7c94 | 69 | |
spinal | 13:8ce494870ba6 | 70 | ss[s] = (snd[s].currentSound[(snd[s].soundPoint*snd[s].speed)>>8]*snd[s].volume>>8) * snd[s].playSample; |
spinal | 14:97a5deea7c94 | 71 | |
spinal | 13:8ce494870ba6 | 72 | ++snd[s].soundPoint; |
spinal | 13:8ce494870ba6 | 73 | if(snd[s].soundPoint >= snd[s].currentSoundSize){ |
spinal | 13:8ce494870ba6 | 74 | if(snd[s].repeat){ |
spinal | 13:8ce494870ba6 | 75 | snd[s].soundPoint=0; |
spinal | 13:8ce494870ba6 | 76 | }else{ |
spinal | 13:8ce494870ba6 | 77 | snd[s].playSample=0; |
spinal | 13:8ce494870ba6 | 78 | snd[s].soundPoint=0; |
spinal | 13:8ce494870ba6 | 79 | } |
spinal | 13:8ce494870ba6 | 80 | } |
spinal | 13:8ce494870ba6 | 81 | } |
spinal | 13:8ce494870ba6 | 82 | |
spinal | 14:97a5deea7c94 | 83 | temp = (ss[0] + ss[1] + ss[2] + ss[3]) - ((ss[0] * ss[1] * ss[2] * ss[3])/256); |
spinal | 13:8ce494870ba6 | 84 | |
spinal | 13:8ce494870ba6 | 85 | return temp; |
spinal | 13:8ce494870ba6 | 86 | } |
spinal | 13:8ce494870ba6 | 87 | |
spinal | 14:97a5deea7c94 | 88 | |
spinal | 14:97a5deea7c94 | 89 | void updateAudioBuffer(){ |
spinal | 14:97a5deea7c94 | 90 | // when updating the audio buffer, I split the buffer into 4 and fill |
spinal | 14:97a5deea7c94 | 91 | // a part that isn't being played, so there are no sync issues |
spinal | 13:8ce494870ba6 | 92 | |
spinal | 14:97a5deea7c94 | 93 | int quart = soundbufindex / 512; |
spinal | 14:97a5deea7c94 | 94 | int sndOffset[]={1024,1536,0,512}; |
spinal | 14:97a5deea7c94 | 95 | |
spinal | 14:97a5deea7c94 | 96 | // only update if the current playback pointer is nowhere near where we want to fill |
spinal | 13:8ce494870ba6 | 97 | if(oldQuart != quart){ |
spinal | 13:8ce494870ba6 | 98 | oldQuart = quart; |
spinal | 14:97a5deea7c94 | 99 | for(int t=0; t<=SBUFSIZE/4;){ |
spinal | 13:8ce494870ba6 | 100 | uint8_t sample = mixSound(t); |
spinal | 13:8ce494870ba6 | 101 | soundbuf[t+sndOffset[quart]] = sample; |
spinal | 13:8ce494870ba6 | 102 | t++; |
spinal | 13:8ce494870ba6 | 103 | } |
spinal | 13:8ce494870ba6 | 104 | } |
spinal | 13:8ce494870ba6 | 105 | } |
spinal | 13:8ce494870ba6 | 106 | |
spinal | 13:8ce494870ba6 | 107 | void update_tune(){ |
spinal | 12:37d999e445ad | 108 | |
spinal | 14:97a5deea7c94 | 109 | char pat = my_pattern[pattern]; |
spinal | 14:97a5deea7c94 | 110 | |
spinal | 13:8ce494870ba6 | 111 | for(int t=0; t<4; t++){ |
spinal | 14:97a5deea7c94 | 112 | int note = tune[pat][currentLine][t][0]; |
spinal | 14:97a5deea7c94 | 113 | int octave = tune[pat][currentLine][t][1]; // no longer used |
spinal | 14:97a5deea7c94 | 114 | int volume = tune[pat][currentLine][t][2];// max volume from xm/mod was 64 |
spinal | 14:97a5deea7c94 | 115 | int instrument = tune[pat][currentLine][t][3]; |
spinal | 13:8ce494870ba6 | 116 | |
spinal | 13:8ce494870ba6 | 117 | if(note > 0){ |
spinal | 14:97a5deea7c94 | 118 | int speed = note_speed[(note-1)+12*octave]; |
spinal | 14:97a5deea7c94 | 119 | |
spinal | 13:8ce494870ba6 | 120 | switch(instrument){ |
spinal | 13:8ce494870ba6 | 121 | case 1: |
spinal | 13:8ce494870ba6 | 122 | playSound(t, s_01, sizeof(s_01), volume, speed, sampleRepeat[0]); |
spinal | 13:8ce494870ba6 | 123 | break; |
spinal | 13:8ce494870ba6 | 124 | case 2: |
spinal | 13:8ce494870ba6 | 125 | playSound(t, s_02, sizeof(s_02), volume, speed, sampleRepeat[1]); |
spinal | 13:8ce494870ba6 | 126 | break; |
spinal | 13:8ce494870ba6 | 127 | case 3: |
spinal | 13:8ce494870ba6 | 128 | playSound(t, s_03, sizeof(s_03), volume, speed, sampleRepeat[2]); |
spinal | 13:8ce494870ba6 | 129 | break; |
spinal | 13:8ce494870ba6 | 130 | case 4: |
spinal | 13:8ce494870ba6 | 131 | playSound(t, s_04, sizeof(s_04), volume, speed, sampleRepeat[3]); |
spinal | 13:8ce494870ba6 | 132 | break; |
spinal | 13:8ce494870ba6 | 133 | } |
spinal | 14:97a5deea7c94 | 134 | |
spinal | 13:8ce494870ba6 | 135 | } |
spinal | 14:97a5deea7c94 | 136 | if(volume >= 128){ |
spinal | 14:97a5deea7c94 | 137 | snd[t].volume = volume-128; |
spinal | 14:97a5deea7c94 | 138 | } |
spinal | 13:8ce494870ba6 | 139 | } |
spinal | 13:8ce494870ba6 | 140 | |
spinal | 14:97a5deea7c94 | 141 | if(currentLine++==patternLength){ |
spinal | 13:8ce494870ba6 | 142 | currentLine=0; |
spinal | 14:97a5deea7c94 | 143 | if(pattern++==sizeof(my_pattern))pattern=loopTo; |
spinal | 13:8ce494870ba6 | 144 | } |
spinal | 13:8ce494870ba6 | 145 | } |
spinal | 12:37d999e445ad | 146 | |
spinal | 12:37d999e445ad | 147 | |
spinal | 14:97a5deea7c94 | 148 | |
spinal | 14:97a5deea7c94 | 149 | |
spinal | 12:37d999e445ad | 150 | int main () |
spinal | 12:37d999e445ad | 151 | { |
spinal | 12:37d999e445ad | 152 | mygame.begin(); |
spinal | 13:8ce494870ba6 | 153 | mygame.setFrameRate(255); |
spinal | 13:8ce494870ba6 | 154 | |
spinal | 13:8ce494870ba6 | 155 | // Init audio stream. |
spinal | 13:8ce494870ba6 | 156 | pokPlayStream(); // activate stream |
spinal | 13:8ce494870ba6 | 157 | mygame.sound.ampEnable(true); |
spinal | 13:8ce494870ba6 | 158 | mygame.sound.playMusicStream(); |
spinal | 14:97a5deea7c94 | 159 | |
spinal | 14:97a5deea7c94 | 160 | // check and update the sound buffer as often as we can |
spinal | 14:97a5deea7c94 | 161 | soundPlay.attach(&updateAudioBuffer, 0.0001); |
spinal | 14:97a5deea7c94 | 162 | musicTimer.attach(&update_tune, 0.055); |
spinal | 13:8ce494870ba6 | 163 | |
spinal | 14:97a5deea7c94 | 164 | d.color = 1; |
spinal | 11:a573cacdc078 | 165 | |
spinal | 12:37d999e445ad | 166 | while (mygame.isRunning()) |
spinal | 12:37d999e445ad | 167 | { |
spinal | 12:37d999e445ad | 168 | if (mygame.update()) |
spinal | 12:37d999e445ad | 169 | { |
spinal | 14:97a5deea7c94 | 170 | |
spinal | 12:37d999e445ad | 171 | } |
spinal | 12:37d999e445ad | 172 | } |
spinal | 11:a573cacdc078 | 173 | } |
spinal | 11:a573cacdc078 | 174 | |
spinal | 11:a573cacdc078 | 175 |