boop/boop/audio/sid.c
2017-07-16 11:18:43 +02:00

165 lines
4.4 KiB
C

/*
sid.c - tone encoder routines
Copyright (C) 2008 Telekatz <telekatz@gmx.de>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "irq.h"
#include "sid.h"
#include "sound.h"
#include "soundirq.h"
#include "lpc2220.h"
#include "timerfuncs.h"
unsigned int playtone_cb;
unsigned char *playtone[3];
unsigned char playstate;
unsigned char tonelen[3];
unsigned short playcounter;
unsigned short playcountermax;
const unsigned short AttackRate[16] = {19531,9766,2441,1628,1028,673,574,488,391,156,78,49,39,13,8,5};
const unsigned short DecayReleaseRate[16] = {6510,1628,814,543,343,233,191,163,130,52,16,13,4,3,2};
const unsigned char song2[] = { note_d,2, note_e,2, note_f,2, note_e,2, note_d,2, note_g,2, note_f,2, note_e,2,
note_d,2, note_e,2, note_f,2, note_g,2, note_a,2, note_g,2, note_f,2, note_e,2,
note_d,2, note_e,2, note_f,2, note_e,2, note_d,2, note_g,2, note_f,2, note_e,2,
note_cis,2, note_d,2, note_e,2, note_f,2, note_g,2, note_a,2, note_f,2, note_e,2,0};
const unsigned char song3[] = { note_0,1, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2,
note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2,
note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2,
note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,2, note_c,1,0};
const unsigned short notes[] = {0,4455,4720,5001,5298,5613,5947,6301,6676,7072,7493,7939,8411,0};
void SIDsetfrq(unsigned char voice, unsigned short frq) {
if (voice < voices) {
SID.reg[(voice * 7) + REG_FREQhi] = frq>>8;
SID.reg[(voice * 7) + REG_FREQlo] = frq & 0xFF;
}
}
void SIDsetadsr(unsigned char voice,unsigned char attack, unsigned char decay, unsigned char sustain, unsigned char release) {
if (voice < voices) {
SID.reg[(voice * 7) + REG_AttackDecay] = (attack<<4) + (decay&0x0f);
SID.reg[(voice * 7) + REG_SustainRelease] = (sustain<<4) + (release&0x0f);
}
}
void SIDsetwave(unsigned char voice,unsigned char wave) {
if (voice < voices) {
SID.reg[(voice * 7)+REG_Control] &= 0x0f;
SID.reg[(voice * 7)+REG_Control] |= wave;
}
}
void SIDplaytone(unsigned int cb) {
unsigned char tone;
unsigned char x;
switch (playstate) {
case 0x01:
playstate++;
setCBIntervall(playtone_cb,48);
for (x=0; x<3; x++) {
if (playtone[x]) {
if (!tonelen[x]) {
tone = *playtone[x];
if (tone) {
playtone[x]++;
tonelen[x] = *playtone[x];
playtone[x]++;
SIDsetfrq(x,notes[tone]);
SID.reg[(x*7)+REG_Control] |= GATE;
}
else {
playstate = 0x00;
playtone[0] = 0;
playtone[1] = 0;
playtone[2] = 0;
removeTimerCB(playtone_cb);
}
}
}
}
break;
case 0x02:
playstate = 0x01;
for (x=0; x<3; x++) {
if (playtone[x]) {
tonelen[x]--;
if (!tonelen[x])
SID.reg[(x*7)+REG_Control] &= ~GATE;
}
}
setCBIntervall(playtone_cb,2);
break;
default:
playstate = 0x00;
removeTimerCB(playtone_cb);
}
}
void SIDplaydump(unsigned int cb) {
unsigned char x;
if (playcounter++ < playcountermax) {
for (x=0;x<14;x++) {
SID.reg[x] = *playtone[0];
playtone[0]++;
}
}
else {
SID.reg[REG_Control] &= ~GATE;
SID.reg[7+REG_Control] &= ~GATE;
SID.reg[14+REG_Control] &= ~GATE;
playstate = 0x00;
playtone[0] =0;
removeTimerCB(playtone_cb);
}
}
void beepEnd(unsigned int cb) {
SID.reg[REG_Control] &= ~GATE;
SID.flags |= SID_AUTO_OFF;
removeTimerCB(cb);
}
void beep(unsigned char n) {
switch(n) {
case 1:
SIDsetwave(0,TRIANGLE);
SIDsetadsr(0,0,10,0,10);
SIDsetfrq(0,8411);
break;
default:
SIDsetwave(0,SAWTOOTH);
SIDsetadsr(0,1,5,10,5);
SIDsetfrq(0,5001);
break;
}
//PWMPR = 0;
switchSound(SOUND_ON);
SID.flags |= SIDenable;
SID.reg[REG_Control] |= GATE;
startCB(addTimerCB(beepEnd, 20));
}