diff --git a/sound-driver/ay_3_8913.c b/sound-driver/ay_3_8913.c index 80ecf43..b00dd6a 100644 --- a/sound-driver/ay_3_8913.c +++ b/sound-driver/ay_3_8913.c @@ -56,7 +56,7 @@ const uint16_t frequencyCodes[8][12] = { #define R15 015 #define ENVELOPE_SHAPE_REG R15 -uint8_t psgShadowRegisters[14]; +uint8_t psgShadowRegisters[2][14]; inline static void BUS_OP_NACT() { BUS_CTRL_REG &= ~(BDIR | BC1); @@ -94,16 +94,20 @@ asm volatile ( } #endif -static uint8_t psgReadShadow(uint8_t address) { - return psgShadowRegisters[address]; +static uint8_t psgReadShadow(uint8_t chip, uint8_t address) { + return psgShadowRegisters[chip][address]; } -static void psgWrite(uint8_t address, uint8_t data) { - psgShadowRegisters[address] = data; +static void psgWrite(uint8_t chip, uint8_t address, uint8_t data) { + psgShadowRegisters[chip][address] = data; // according to "State Timing" (p. 15) of datasheet - BUS_OP_CS1_ENABLE(); + if (chip == 0) { + BUS_OP_CS0_ENABLE(); + } else { + BUS_OP_CS1_ENABLE(); + } // put bus into inactive state BUS_OP_NACT(); @@ -126,26 +130,30 @@ static void psgWrite(uint8_t address, uint8_t data) { // set inactive again BUS_OP_NACT(); - BUS_OP_CS1_DISABLE(); -} - -static void psgWriteFrequency(uint8_t channel, uint16_t frequencyCode) { - psgWrite(CHANNEL_A_TONE_PERIOD_FINE_REG + (channel * 2), (frequencyCode & 0x00ff)); - psgWrite(CHANNEL_A_TONE_PERIOD_COARSE_REG + (channel * 2), ((frequencyCode >> 8) & 0x000f)); -} - -void psgPlayTone(uint8_t channel, uint8_t volume, t_octave octave, t_note note) { - if (note == e_Pause) { - psgWrite(_ENABLE_REG, psgReadShadow(_ENABLE_REG) | (1 << channel)); + if (chip == 0) { + BUS_OP_CS0_DISABLE(); } else { - psgWrite(_ENABLE_REG, psgReadShadow(_ENABLE_REG) & ~(1 << channel)); - psgAmplitude(channel, volume); - psgWriteFrequency(channel, frequencyCodes[octave][note]); + BUS_OP_CS1_DISABLE(); } } -void psgAmplitude(uint8_t channel, uint8_t volume) { - psgWrite(CHANNEL_A_AMPLITUDE_REG + channel, volume); +static void psgWriteFrequency(uint8_t chip, uint8_t channel, uint16_t frequencyCode) { + psgWrite(chip, CHANNEL_A_TONE_PERIOD_FINE_REG + (channel * 2), (frequencyCode & 0x00ff)); + psgWrite(chip, CHANNEL_A_TONE_PERIOD_COARSE_REG + (channel * 2), ((frequencyCode >> 8) & 0x000f)); +} + +void psgPlayTone(uint8_t chip, uint8_t channel, uint8_t volume, t_octave octave, t_note note) { + if (note == e_Pause) { + psgWrite(chip, _ENABLE_REG, psgReadShadow(chip, _ENABLE_REG) | (1 << channel)); + } else { + psgWrite(chip, _ENABLE_REG, psgReadShadow(chip, _ENABLE_REG) & ~(1 << channel)); + psgAmplitude(chip, channel, volume); + psgWriteFrequency(chip, channel, frequencyCodes[octave][note]); + } +} + +void psgAmplitude(uint8_t chip, uint8_t channel, uint8_t volume) { + psgWrite(chip, CHANNEL_A_AMPLITUDE_REG + channel, volume); } void psgInit() { @@ -154,18 +162,6 @@ void psgInit() { P2SEL = 0; P2SEL2 = 0; - // sound chip reset - // BIT2: /RST - // P1DIR |= BIT2; - -#if 0 - // put sound chip into reset state - P1OUT &= ~BIT2; - delay(); - delay(); - delay(); -#endif - // bus control lines // BIT3: BC1 // BIT1: BDIR @@ -176,15 +172,8 @@ void psgInit() { // put bus into inactive state BUS_CTRL_REG &= ~(BDIR | BC1); -#if 0 - // release sound chip from reset state - P1OUT |= BIT2; - delay(); - delay(); - delay(); -#endif - // disable everything - psgWrite(_ENABLE_REG, 0xff); + psgWrite(0, _ENABLE_REG, 0xff); + psgWrite(1, _ENABLE_REG, 0xff); } diff --git a/sound-driver/melody.c b/sound-driver/melody.c index 5adb399..b02b9e1 100644 --- a/sound-driver/melody.c +++ b/sound-driver/melody.c @@ -74,27 +74,29 @@ const t_tone notes[] = { */ const t_tone tonleiter[] = { - { .octave = e_O_6, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_6, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_E, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_F, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_G, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_A, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_6, .note = e_H, .length = e_L_1_16, .legato = false, .staccato = false }, { .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false }, + { .octave = e_O_Null, .note = e_Null, .length = e_L_StopMark,.legato = false, .staccato = false }, + { .octave = e_O_Null, .note = e_Null, .length = e_L_EndMark, .legato = false, .staccato = false }, }; const t_tone tonleiter2[] = { - { .octave = e_O_4, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_4, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_E, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_F, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_G, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_A, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_4, .note = e_H, .length = e_L_1_16, .legato = false, .staccato = false }, { .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false }, @@ -102,13 +104,13 @@ const t_tone tonleiter2[] = { }; const t_tone tonleiter3[] = { - { .octave = e_O_5, .note = e_C, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_D, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_E, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_F, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_G, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_A, .length = e_L_1_4, .legato = false, .staccato = false }, - { .octave = e_O_5, .note = e_H, .length = e_L_1_4, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_C, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_D, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_E, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_F, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_G, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_A, .length = e_L_1_16, .legato = false, .staccato = false }, + { .octave = e_O_5, .note = e_H, .length = e_L_1_16, .legato = false, .staccato = false }, { .octave = e_O_Null, .note = e_Null, .length = e_L_SyncMark,.legato = false, .staccato = false }, @@ -1033,19 +1035,20 @@ const t_tone voice3[] = { }; t_melodies tetrisTheme = { - .melodies = { { .amplitude = 3, .tones = voice1 }, { .amplitude = 3, .tones = voice2 }, { .amplitude = 3, .tones = voice3 } }, + .melodies = { { .chip = 0, .amplitude = 3, .tones = voice1 }, { .chip = 0, .amplitude = 3, .tones = voice2 }, { .chip = 0, .amplitude = 3, .tones = voice3 } }, .numOfMelodies = 3, .pace = 160 }; t_melodies tonleiterTheme = { - .melodies = { { .amplitude = 3, .tones = tonleiter }, { .amplitude = 3, .tones = tonleiter2 }, { .amplitude = 3, .tones = tonleiter3 } }, + .melodies = { { .chip = 1, .amplitude = 3, .tones = tonleiter }, { .chip = 1, .amplitude = 3, .tones = tonleiter2 }, { .chip = 1, .amplitude = 3, .tones = tonleiter3 } }, .numOfMelodies = 3, .pace = 160 }; void melodyInit() { sequencerPlayMelodies(&tetrisTheme); + sequencerPlayMelodies(&tonleiterTheme); } diff --git a/sound-driver/psg.h b/sound-driver/psg.h index ff9361c..79bcda9 100644 --- a/sound-driver/psg.h +++ b/sound-driver/psg.h @@ -39,8 +39,8 @@ typedef enum { void psgInit(); -void psgPlayTone(uint8_t channel, uint8_t volume, t_octave octave, t_note note); -void psgAmplitude(uint8_t channel, uint8_t volume); +void psgPlayTone(uint8_t chip, uint8_t channel, uint8_t volume, t_octave octave, t_note note); +void psgAmplitude(uint8_t chip, uint8_t channel, uint8_t volume); #endif // _PSG_H_ diff --git a/sound-driver/sequencer.c b/sound-driver/sequencer.c index 95309fa..94560b8 100644 --- a/sound-driver/sequencer.c +++ b/sound-driver/sequencer.c @@ -43,11 +43,13 @@ void sequencerExec(void *handle) { } melodies->sync -= 1; melody->state = e_Sync; + } else if (melody->tones[melody->idx].length == e_L_StopMark) { + melody->state = e_Terminate; } else { if (melody->tones[melody->idx].length == e_L_EndMark) { melody->idx = 0; } - psgPlayTone(channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note); + psgPlayTone(melody->chip, channel, melody->amplitude, melody->tones[melody->idx].octave, melody->tones[melody->idx].note); melody->lengthCnt = (melody->tones[melody->idx].staccato) ? (lengths[melody->tones[melody->idx].length] / 2) : lengths[melody->tones[melody->idx].length]; melody->state = e_HoldTone; } @@ -64,7 +66,7 @@ void sequencerExec(void *handle) { } break; case e_StaccatoBreak: - psgPlayTone(channel, 0, e_O_Null, e_Pause); + psgPlayTone(melody->chip, channel, 0, e_O_Null, e_Pause); melody->lengthCnt = lengths[melody->tones[melody->idx].length] / 2; melody->state = e_HoldStaccatoBreak; break; @@ -76,11 +78,14 @@ void sequencerExec(void *handle) { break; case e_SeparateTone: if (! (melody->tones[melody->idx].legato)) { - psgPlayTone(channel, 0, e_O_Null, e_Pause); + psgPlayTone(melody->chip, channel, 0, e_O_Null, e_Pause); } melody->idx += 1; melody->state = e_PlayTone; break; + case e_Terminate: + schDel(melodies->taskId); + break; } } } @@ -94,6 +99,8 @@ uint16_t sequencerPlayMelodies(t_melodies *melodies) { melodies->sync = 0; melodies->firstRun = true; - return schAdd(sequencerExec, (void*) melodies, 0, SEQUENCER_PERIOD); + melodies->taskId = schAdd(sequencerExec, (void*) melodies, 0, SEQUENCER_PERIOD); + + return melodies->taskId; } diff --git a/sound-driver/sequencer.h b/sound-driver/sequencer.h index 114c658..cd429aa 100644 --- a/sound-driver/sequencer.h +++ b/sound-driver/sequencer.h @@ -14,6 +14,7 @@ typedef enum { e_L_1_16 = 4, e_L_1_32 = 5, e_L_LengthEnd = 6, + e_L_StopMark = 253, e_L_EndMark = 254, e_L_SyncMark = 255, } t_noteLength; @@ -33,11 +34,13 @@ typedef enum { e_HoldTone, e_StaccatoBreak, e_HoldStaccatoBreak, - e_SeparateTone + e_SeparateTone, + e_Terminate } t_sequencerState; typedef struct { uint16_t idx; + uint8_t chip; uint16_t lengthCnt; t_sequencerState state; uint8_t amplitude; @@ -47,6 +50,7 @@ typedef struct { #define SEQUENCER_PERIOD 4 // ms #define NUM_OF_CHANNELS 3 typedef struct { + uint8_t taskId; uint8_t numOfMelodies; bool firstRun; uint8_t pace; // quarter notes per minute