attempt at tracker style music
Diff: main.cpp
- Revision:
- 13:8ce494870ba6
- Parent:
- 12:37d999e445ad
- Child:
- 14:97a5deea7c94
- Child:
- 15:209481812170
--- a/main.cpp Sat Oct 20 15:16:16 2018 +0000 +++ b/main.cpp Sat Nov 17 16:33:51 2018 +0000 @@ -1,140 +1,275 @@ #include "Pokitto.h" +#include "HWSound.h" +#include "snd.h" +#include "tune.h" Pokitto::Core mygame; Pokitto::Display d; -mbed::DigitalOut jh_rumble(EXT0); -mbed::DigitalIn jh_b1(EXT15); -mbed::DigitalIn jh_b2(EXT14); -mbed::AnalogIn jh_x(EXT1); -mbed::AnalogIn jh_y(EXT2); +//------------------------[ 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 +} -#define ANALOG 256 -#define DECAY .85 -#define SEGSIZE 7 -#define number_of_segments 10 -#define MOVEANGLE .25 +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; +} + -//Sprite structure -typedef struct -{ - int x,y,oldx,oldy; //location - int xSpeed, ySpeed; //speed - char frame; // body gfx -}Sprite; -Sprite marbles[number_of_segments]; +typedef struct{ + bool playSample; + int soundPoint; + const uint8_t *currentSound; + int currentSoundSize; + int volume; + int speed; + int repeat; +} sampletype; + +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# -bool move_tail(void){ - int pos_x,pos_y; - int bodySize = SEGSIZE*512; - bool collision = false; - for(int t=1; t<number_of_segments; t++){ -// float rotation = atan2((float)marbles[t].y-marbles[t-1].y,(float)marbles[t].x-marbles[t-1].x); +void emptyBuffer(){ + for(int t=0; t<SBUFSIZE;){ + soundbuf[++t]=0; + } + + for(int t=0; t<4; t++){ + snd[t].playSample=0; + } + +} + +uint8_t playSound(int channel, const unsigned char *sound, uint16_t soundSize, int volume = 255, int speed=255, int repeat=0){ /* - // rotate the head graphic - if(t==1) - { - int rot = rotation*(180 / 3.14159); - rot+=90; - if(rot<0)rot+=360; - if(rot>360)rot-=360; - rot/=10; - rot+=3; -// PA_SetSpriteAnimEx(1,0,16,16,1,rot); + 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; - float x1 = marbles[t].x; - float y1 = marbles[t].y; - float x2 = marbles[t-1].x; - float y2 = marbles[t-1].y; - float rotation = atan2(y1-y2,x1-x2); + return channel; +} + +uint8_t mixSound(int samplePos) +{ + int temp = 0; + int ss[4]; - for(int s=0; s<number_of_segments; s++){ - if(s<t-1 || s>t+1){ - double square_difference_x = (x1 - marbles[s].x) * (x1 - marbles[s].x); - double square_difference_y = (y1 - marbles[s].y) * (y1 - marbles[s].y); - double value = sqrt(square_difference_x + square_difference_y); - - if(value < bodySize+1){ - pos_x = x2 + bodySize * cos(rotation+MOVEANGLE); - pos_y = y2 + bodySize * sin(rotation+MOVEANGLE); + 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; + } + } + } + - double square_difference_x = (pos_x - marbles[s].x) * (pos_x - marbles[s].x); - double square_difference_y = (pos_y - marbles[s].y) * (pos_y - marbles[s].y); - double value2 = sqrt(square_difference_x + square_difference_y); - - if(value < value2)rotation+=MOVEANGLE; - if(value > value2)rotation-=MOVEANGLE; - collision=true; - } - } +// 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; } - pos_x = marbles[t-1].x + bodySize * cos(rotation); - pos_y = marbles[t-1].y + bodySize * sin(rotation); - marbles[t].x = pos_x; - marbles[t].y = pos_y; +} - } // for t... - return collision; +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++; + } + } + +} + +void update_tune(){ -}// end function - + 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 + + 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; + } + } + + snd[t].volume = volume; + + } + + if(currentLine++==63){ + currentLine=0; + pattern++; + } +} int main () { mygame.begin(); + mygame.setFrameRate(255); +// emptyBuffer(); // clear the sound buffer - int JCX = ((jh_x.read()*ANALOG)); - int JCY = ((jh_y.read()*ANALOG)); + // 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(); + + + uint32_t nextBufferIndexToFill = 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(); + } + if (mygame.update()) { + // update buttons + myPad = updateButtons(myPad); + UpdatePad(myPad); - int xd = ((jh_x.read()*ANALOG)-JCX)*4; - int yd = ((jh_y.read()*ANALOG)-JCY)*4; - - // motion gravity etc. - marbles[0].xSpeed += -xd; - marbles[0].ySpeed += yd; - - // add some dampening to speed - marbles[0].xSpeed *= DECAY; - marbles[0].ySpeed *= DECAY; - - marbles[0].x += marbles[0].xSpeed; - marbles[0].y += marbles[0].ySpeed; - - - jh_rumble.write(mygame.buttons.aBtn()); d.color = 1; - d.printf("Joy X: %d\n",xd); - d.printf("Joy Y: %d\n",yd); - d.printf("B1: %d\n",jh_b1.read()); - d.printf("B2: %d\n",jh_b2.read()); - d.printf("A to Rumble!\n"); - - - // loop until the snake no longer collides with itself. - while(move_tail()){} - - for(int t=0; t<number_of_segments; t++){ - d.color = 0; - if(t==0) d.color = 1; - d.fillCircle(marbles[t].x>>8,marbles[t].y>>8,SEGSIZE); - d.color = 2; - d.drawCircle(marbles[t].x>>8,marbles[t].y>>8,SEGSIZE); - } - - - + d.printf("Tick %d", mytick); + d.printf("Line %d", currentLine); } }