Improved FPS test plugin: * Better precision for low frame rates (take extra ticks...
[Rockbox.git] / apps / codecs / sid.c
blob1c98714357258f1d4ec469dc43a19cf5ced3d8a8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * SID Codec for rockbox based on the TinySID engine
12 * Written by Tammo Hinrichs (kb) and Rainer Sinsch in 1998-1999
13 * Ported to rockbox on 14 April 2006
16 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 /*****************************
25 * kb explicitly points out that this emulation sounds crappy, though
26 * we decided to put it open source so everyone can enjoy sidmusic
27 * on rockbox
29 *****************************/
31 /*********************
32 * v1.1
33 * Added 16-04-2006: Rainer Sinsch
34 * Removed all time critical floating point operations and
35 * replaced them with quick & dirty integer calculations
37 * Added 17-04-2006: Rainer Sinsch
38 * Improved quick & dirty integer calculations for the resonant filter
39 * Improved audio quality by 4 bits
41 * v1.2
42 * Added 17-04-2006: Dave Chapman
43 * Improved file loading
45 * Added 17-04-2006: Rainer Sinsch
46 * Added sample routines
47 * Added cia timing routines
48 * Added fast forwarding capabilities
49 * Corrected bug in sid loading
51 * v1.2.1
52 * Added 04-05-2006: Rainer Sinsch
53 * Implemented Marco Alanens suggestion for subsong selection:
54 * Select the subsong by seeking: Each second represents a subsong
56 **************************/
58 #define USE_FILTER
60 #include "debug.h"
61 #include "codeclib.h"
62 #include <inttypes.h>
64 CODEC_HEADER
66 #define CHUNK_SIZE (1024*2)
68 /* This codec supports SID Files:
72 static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
74 /* Static buffer for the plain SID-File */
75 static unsigned char sidfile[0x10000];
77 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
79 #define FLAG_N 128
80 #define FLAG_V 64
81 #define FLAG_B 16
82 #define FLAG_D 8
83 #define FLAG_I 4
84 #define FLAG_Z 2
85 #define FLAG_C 1
87 #define imp 0
88 #define imm 1
89 #define _abs 2
90 #define absx 3
91 #define absy 4
92 #define zp 6
93 #define zpx 7
94 #define zpy 8
95 #define ind 9
96 #define indx 10
97 #define indy 11
98 #define acc 12
99 #define rel 13
101 enum {
102 adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, brk, bvc, bvs, clc,
103 cld, cli, clv, cmp, cpx, cpy, dec, dex, dey, eor, inc, inx, iny, jmp,
104 jsr, lda, ldx, ldy, lsr, _nop, ora, pha, php, pla, plp, rol, ror, rti,
105 rts, sbc, sec, sed, sei, sta, stx, sty, tax, tay, tsx, txa, txs, tya,
109 /* SID register definition */
110 struct s6581 {
111 struct sidvoice {
112 unsigned short freq;
113 unsigned short pulse;
114 unsigned char wave;
115 unsigned char ad;
116 unsigned char sr;
117 } v[3];
118 unsigned char ffreqlo;
119 unsigned char ffreqhi;
120 unsigned char res_ftv;
121 unsigned char ftp_vol;
124 /* internal oscillator def */
125 struct sidosc {
126 unsigned long freq;
127 unsigned long pulse;
128 unsigned char wave;
129 unsigned char filter;
130 unsigned long attack;
131 unsigned long decay;
132 unsigned long sustain;
133 unsigned long release;
134 unsigned long counter;
135 signed long envval;
136 unsigned char envphase;
137 unsigned long noisepos;
138 unsigned long noiseval;
139 unsigned char noiseout;
142 /* internal filter def */
143 struct sidflt {
144 int freq;
145 unsigned char l_ena;
146 unsigned char b_ena;
147 unsigned char h_ena;
148 unsigned char v3ena;
149 int vol;
150 int rez;
151 int h;
152 int b;
153 int l;
156 /* ------------------------ pseudo-constants (depending on mixing freq) */
157 int mixing_frequency IDATA_ATTR;
158 unsigned long freqmul IDATA_ATTR;
159 int filtmul IDATA_ATTR;
160 unsigned long attacks [16] IDATA_ATTR;
161 unsigned long releases[16] IDATA_ATTR;
163 /* ------------------------------------------------------------ globals */
164 struct s6581 sid IDATA_ATTR;
165 struct sidosc osc[3] IDATA_ATTR;
166 struct sidflt filter IDATA_ATTR;
168 /* ------------------------------------------------------ C64 Emu Stuff */
169 unsigned char bval IDATA_ATTR;
170 unsigned short wval IDATA_ATTR;
171 /* -------------------------------------------------- Register & memory */
172 unsigned char a,x,y,s,p IDATA_ATTR;
173 unsigned short pc IDATA_ATTR;
175 unsigned char memory[65536];
177 /* ----------------------------------------- Variables for sample stuff */
178 static int sample_active IDATA_ATTR;
179 static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
180 static int fracPos IDATA_ATTR; /* Fractal position of sample */
181 static int sample_period IDATA_ATTR;
182 static int sample_repeats IDATA_ATTR;
183 static int sample_order IDATA_ATTR;
184 static int sample_nibble IDATA_ATTR;
186 static int internal_period, internal_order, internal_start, internal_end,
187 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
189 /* ---------------------------------------------------------- constants */
190 static const float attackTimes[16] ICONST_ATTR =
192 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
193 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
194 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
195 0.977715461, 2.93364701, 4.88907793, 7.82272493
197 static const float decayReleaseTimes[16] ICONST_ATTR =
199 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
200 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
201 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
204 static const int opcodes[256] ICONST_ATTR = {
205 brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
206 bpl,ora,xxx,xxx,xxx,ora,asl,xxx,clc,ora,xxx,xxx,xxx,ora,asl,xxx,
207 jsr,_and,xxx,xxx,bit,_and,rol,xxx,plp,_and,rol,xxx,bit,_and,rol,xxx,
208 bmi,_and,xxx,xxx,xxx,_and,rol,xxx,sec,_and,xxx,xxx,xxx,_and,rol,xxx,
209 rti,eor,xxx,xxx,xxx,eor,lsr,xxx,pha,eor,lsr,xxx,jmp,eor,lsr,xxx,
210 bvc,eor,xxx,xxx,xxx,eor,lsr,xxx,cli,eor,xxx,xxx,xxx,eor,lsr,xxx,
211 rts,adc,xxx,xxx,xxx,adc,ror,xxx,pla,adc,ror,xxx,jmp,adc,ror,xxx,
212 bvs,adc,xxx,xxx,xxx,adc,ror,xxx,sei,adc,xxx,xxx,xxx,adc,ror,xxx,
213 xxx,sta,xxx,xxx,sty,sta,stx,xxx,dey,xxx,txa,xxx,sty,sta,stx,xxx,
214 bcc,sta,xxx,xxx,sty,sta,stx,xxx,tya,sta,txs,xxx,xxx,sta,xxx,xxx,
215 ldy,lda,ldx,xxx,ldy,lda,ldx,xxx,tay,lda,tax,xxx,ldy,lda,ldx,xxx,
216 bcs,lda,xxx,xxx,ldy,lda,ldx,xxx,clv,lda,tsx,xxx,ldy,lda,ldx,xxx,
217 cpy,cmp,xxx,xxx,cpy,cmp,dec,xxx,iny,cmp,dex,xxx,cpy,cmp,dec,xxx,
218 bne,cmp,xxx,xxx,xxx,cmp,dec,xxx,cld,cmp,xxx,xxx,xxx,cmp,dec,xxx,
219 cpx,sbc,xxx,xxx,cpx,sbc,inc,xxx,inx,sbc,_nop,xxx,cpx,sbc,inc,xxx,
220 beq,sbc,xxx,xxx,xxx,sbc,inc,xxx,sed,sbc,xxx,xxx,xxx,sbc,inc,xxx
224 static const int modes[256] ICONST_ATTR = {
225 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
226 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
227 _abs,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
228 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
229 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
230 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
231 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,ind,_abs,_abs,xxx,
232 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
233 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
234 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
235 imm,indx,imm,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
236 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,absx,absx,absy,xxx,
237 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
238 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
239 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
240 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx
243 /* Routines for quick & dirty float calculation */
245 static inline int quickfloat_ConvertFromInt(int i)
247 return (i<<16);
249 static inline int quickfloat_ConvertFromFloat(float f)
251 return (int)(f*(1<<16));
253 static inline int quickfloat_Multiply(int a, int b)
255 return (a>>8)*(b>>8);
257 static inline int quickfloat_ConvertToInt(int i)
259 return (i>>16);
262 /* Get the bit from an unsigned long at a specified position */
263 static inline unsigned char get_bit(unsigned long val, unsigned char b)
265 return (unsigned char) ((val >> b) & 1);
269 static inline int GenerateDigi(int sIn)
271 static int last_sample = 0;
272 static int sample = 0;
274 if (!sample_active) return(sIn);
276 if ((sample_position < sample_end) && (sample_position >= sample_start))
278 sIn += sample;
280 fracPos += 985248/sample_period;
282 if (fracPos > mixing_frequency)
284 fracPos%=mixing_frequency;
286 last_sample = sample;
288 // N�hstes Samples holen
289 if (sample_order == 0) {
290 sample_nibble++; // Nähstes Sample-Nibble
291 if (sample_nibble==2) {
292 sample_nibble = 0;
293 sample_position++;
296 else {
297 sample_nibble--;
298 if (sample_nibble < 0) {
299 sample_nibble=1;
300 sample_position++;
303 if (sample_repeats)
305 if (sample_position > sample_end)
307 sample_repeats--;
308 sample_position = sample_repeat_start;
310 else sample_active = 0;
313 sample = memory[sample_position&0xffff];
314 if (sample_nibble==1) // Hi-Nibble holen?
315 sample = (sample & 0xf0)>>4;
316 else sample = sample & 0x0f;
318 sample -= 7;
319 sample <<= 10;
323 return (sIn);
326 /* ------------------------------------------------------------- synthesis
327 initialize SID and frequency dependant values */
328 void synth_init(unsigned long mixfrq) ICODE_ATTR;
329 void synth_init(unsigned long mixfrq)
331 int i;
332 mixing_frequency = mixfrq;
333 fracPos = 0;
334 freqmul = 15872000 / mixfrq;
335 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
336 for (i=0;i<16;i++) {
337 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
338 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
340 memset(&sid,0,sizeof(sid));
341 memset(osc,0,sizeof(osc));
342 memset(&filter,0,sizeof(filter));
343 osc[0].noiseval = 0xffffff;
344 osc[1].noiseval = 0xffffff;
345 osc[2].noiseval = 0xffffff;
348 /* render a buffer of n samples with the actual register contents */
349 void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
350 void synth_render (int32_t *buffer, unsigned long len)
352 unsigned long bp;
353 /* step 1: convert the not easily processable sid registers into some
354 more convenient and fast values (makes the thing much faster
355 if you process more than 1 sample value at once) */
356 unsigned char v;
357 for (v=0;v<3;v++) {
358 osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
359 osc[v].filter = get_bit(sid.res_ftv,v);
360 osc[v].attack = attacks[sid.v[v].ad >> 4];
361 osc[v].decay = releases[sid.v[v].ad & 0xf];
362 osc[v].sustain = sid.v[v].sr & 0xf0;
363 osc[v].release = releases[sid.v[v].sr & 0xf];
364 osc[v].wave = sid.v[v].wave;
365 osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
368 #ifdef USE_FILTER
369 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
371 if (filter.freq>quickfloat_ConvertFromInt(1))
372 filter.freq=quickfloat_ConvertFromInt(1);
373 /* the above line isnt correct at all - the problem is that the filter
374 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
375 for 32KHz and lower - well, but sound quality is bad enough then to
376 neglect the fact that the filter doesnt come that high ;) */
377 filter.l_ena = get_bit(sid.ftp_vol,4);
378 filter.b_ena = get_bit(sid.ftp_vol,5);
379 filter.h_ena = get_bit(sid.ftp_vol,6);
380 filter.v3ena = !get_bit(sid.ftp_vol,7);
381 filter.vol = (sid.ftp_vol & 0xf);
382 filter.rez = quickfloat_ConvertFromFloat(1.2f) -
383 quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
385 /* We precalculate part of the quick float operation, saves time in loop later */
386 filter.rez>>=8;
387 #endif
390 /* now render the buffer */
391 for (bp=0;bp<len;bp++) {
392 #ifdef USE_FILTER
393 int outo=0;
394 #endif
395 int outf=0;
396 /* step 2 : generate the two output signals (for filtered and non-
397 filtered) from the osc/eg sections */
398 for (v=0;v<3;v++) {
399 /* update wave counter */
400 osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
401 /* reset counter / noise generator if reset get_bit set */
402 if (osc[v].wave & 0x08) {
403 osc[v].counter = 0;
404 osc[v].noisepos = 0;
405 osc[v].noiseval = 0xffffff;
407 unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
408 /* sync oscillator to refosc if sync bit set */
409 if (osc[v].wave & 0x02)
410 if (osc[refosc].counter < osc[refosc].freq)
411 osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
412 /* generate waveforms with really simple algorithms */
413 unsigned char triout = (unsigned char) (osc[v].counter>>19);
414 if (osc[v].counter>>27)
415 triout^=0xff;
416 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
417 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
419 /* generate noise waveform exactly as the SID does. */
420 if (osc[v].noisepos!=(osc[v].counter>>23))
422 osc[v].noisepos = osc[v].counter >> 23;
423 osc[v].noiseval = (osc[v].noiseval << 1) |
424 (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
425 osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
426 (get_bit(osc[v].noiseval,20) << 6) |
427 (get_bit(osc[v].noiseval,16) << 5) |
428 (get_bit(osc[v].noiseval,13) << 4) |
429 (get_bit(osc[v].noiseval,11) << 3) |
430 (get_bit(osc[v].noiseval, 7) << 2) |
431 (get_bit(osc[v].noiseval, 4) << 1) |
432 (get_bit(osc[v].noiseval, 2) << 0);
434 unsigned char nseout = osc[v].noiseout;
436 /* modulate triangle wave if ringmod bit set */
437 if (osc[v].wave & 0x04)
438 if (osc[refosc].counter < 0x8000000)
439 triout ^= 0xff;
441 /* now mix the oscillators with an AND operation as stated in
442 the SID's reference manual - even if this is completely wrong.
443 well, at least, the $30 and $70 waveform sounds correct and there's
444 no real solution to do $50 and $60, so who cares. */
446 unsigned char outv=0xFF;
447 if (osc[v].wave & 0x10) outv &= triout;
448 if (osc[v].wave & 0x20) outv &= sawout;
449 if (osc[v].wave & 0x40) outv &= plsout;
450 if (osc[v].wave & 0x80) outv &= nseout;
452 /* so now process the volume according to the phase and adsr values */
453 switch (osc[v].envphase) {
454 case 0 : { /* Phase 0 : Attack */
455 osc[v].envval+=osc[v].attack;
456 if (osc[v].envval >= 0xFFFFFF)
458 osc[v].envval = 0xFFFFFF;
459 osc[v].envphase = 1;
461 break;
463 case 1 : { /* Phase 1 : Decay */
464 osc[v].envval-=osc[v].decay;
465 if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
467 osc[v].envval = osc[v].sustain<<16;
468 osc[v].envphase = 2;
470 break;
472 case 2 : { /* Phase 2 : Sustain */
473 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
475 osc[v].envphase = 1;
477 /* :) yes, thats exactly how the SID works. and maybe
478 a music routine out there supports this, so better
479 let it in, thanks :) */
480 break;
482 case 3 : { /* Phase 3 : Release */
483 osc[v].envval-=osc[v].release;
484 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
486 /* the volume offset is because the SID does not
487 completely silence the voices when it should. most
488 emulators do so though and thats the main reason
489 why the sound of emulators is too, err... emulated :) */
490 break;
494 #ifdef USE_FILTER
496 /* now route the voice output to either the non-filtered or the
497 filtered channel and dont forget to blank out osc3 if desired */
499 if (v<2 || filter.v3ena)
501 if (osc[v].filter)
502 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
503 else
504 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
506 #endif
507 #ifndef USE_FILTER
508 /* Don't use filters, just mix all voices together */
509 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
510 #endif
514 #ifdef USE_FILTER
515 /* step 3
516 * so, now theres finally time to apply the multi-mode resonant filter
517 * to the signal. The easiest thing ist just modelling a real electronic
518 * filter circuit instead of fiddling around with complex IIRs or even
519 * FIRs ...
520 * it sounds as good as them or maybe better and needs only 3 MULs and
521 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
522 * Mage messed the whole thing completely up - as the rest of the
523 * emulator.
524 * This filter sounds a lot like the 8580, as the low-quality, dirty
525 * sound of the 6581 is uuh too hard to achieve :) */
527 filter.h = quickfloat_ConvertFromInt(outf) - (filter.b>>8)*filter.rez - filter.l;
528 filter.b += quickfloat_Multiply(filter.freq, filter.h);
529 filter.l += quickfloat_Multiply(filter.freq, filter.b);
531 outf = 0;
533 if (filter.l_ena) outf+=quickfloat_ConvertToInt(filter.l);
534 if (filter.b_ena) outf+=quickfloat_ConvertToInt(filter.b);
535 if (filter.h_ena) outf+=quickfloat_ConvertToInt(filter.h);
537 int final_sample = (filter.vol*(outo+outf));
538 *(buffer+bp)= GenerateDigi(final_sample)<<13;
539 #endif
540 #ifndef USE_FILTER
541 *(buffer+bp) = GenerateDigi(outf)<<3;
542 #endif
549 * C64 Mem Routines
551 static inline unsigned char getmem(unsigned short addr)
553 return memory[addr];
556 static inline void setmem(unsigned short addr, unsigned char value)
558 if ((addr&0xfc00)==0xd400)
560 sidPoke(addr&0x1f,value);
561 /* New SID-Register */
562 if (addr > 0xd418)
564 switch (addr)
566 case 0xd41f: /* Start-Hi */
567 internal_start = (internal_start&0x00ff) | (value<<8); break;
568 case 0xd41e: /* Start-Lo */
569 internal_start = (internal_start&0xff00) | (value); break;
570 case 0xd47f: /* Repeat-Hi */
571 internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
572 case 0xd47e: /* Repeat-Lo */
573 internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
574 case 0xd43e: /* End-Hi */
575 internal_end = (internal_end&0x00ff) | (value<<8); break;
576 case 0xd43d: /* End-Lo */
577 internal_end = (internal_end&0xff00) | (value); break;
578 case 0xd43f: /* Loop-Size */
579 internal_repeat_times = value; break;
580 case 0xd45e: /* Period-Hi */
581 internal_period = (internal_period&0x00ff) | (value<<8); break;
582 case 0xd45d: /* Period-Lo */
583 internal_period = (internal_period&0xff00) | (value); break;
584 case 0xd47d: /* Sample Order */
585 internal_order = value; break;
586 case 0xd45f: /* Sample Add */
587 internal_add = value; break;
588 case 0xd41d: /* Start sampling */
589 sample_repeats = internal_repeat_times;
590 sample_position = internal_start;
591 sample_start = internal_start;
592 sample_end = internal_end;
593 sample_repeat_start = internal_repeat_start;
594 sample_period = internal_period;
595 sample_order = internal_order;
596 switch (value)
598 case 0xfd: sample_active = 0; break;
599 case 0xfe:
600 case 0xff: sample_active = 1; break;
601 default: return;
603 break;
607 else memory[addr]=value;
611 * Poke a value into the sid register
613 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
614 void sidPoke(int reg, unsigned char val)
616 int voice=0;
618 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
619 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
621 switch (reg) {
622 case 0: { /* Set frequency: Low byte */
623 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
624 break;
626 case 1: { /* Set frequency: High byte */
627 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
628 break;
630 case 2: { /* Set pulse width: Low byte */
631 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
632 break;
634 case 3: { /* Set pulse width: High byte */
635 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
636 break;
638 case 4: { sid.v[voice].wave = val;
639 /* Directly look at GATE-Bit!
640 * a change may happen twice or more often during one cpujsr
641 * Put the Envelope Generator into attack or release phase if desired
643 if ((val & 0x01) == 0) osc[voice].envphase=3;
644 else if (osc[voice].envphase==3) osc[voice].envphase=0;
645 break;
648 case 5: { sid.v[voice].ad = val; break;}
649 case 6: { sid.v[voice].sr = val; break;}
651 case 21: { sid.ffreqlo = val; break; }
652 case 22: { sid.ffreqhi = val; break; }
653 case 23: { sid.res_ftv = val; break; }
654 case 24: { sid.ftp_vol = val; break;}
656 return;
659 static inline unsigned char getaddr(int mode)
661 unsigned short ad,ad2;
662 switch(mode)
664 case imp:
665 return 0;
666 case imm:
667 return getmem(pc++);
668 case _abs:
669 ad=getmem(pc++);
670 ad|=256*getmem(pc++);
671 return getmem(ad);
672 case absx:
673 ad=getmem(pc++);
674 ad|=256*getmem(pc++);
675 ad2=ad+x;
676 return getmem(ad2);
677 case absy:
678 ad=getmem(pc++);
679 ad|=256*getmem(pc++);
680 ad2=ad+y;
681 return getmem(ad2);
682 case zp:
683 ad=getmem(pc++);
684 return getmem(ad);
685 case zpx:
686 ad=getmem(pc++);
687 ad+=x;
688 return getmem(ad&0xff);
689 case zpy:
690 ad=getmem(pc++);
691 ad+=y;
692 return getmem(ad&0xff);
693 case indx:
694 ad=getmem(pc++);
695 ad+=x;
696 ad2=getmem(ad&0xff);
697 ad++;
698 ad2|=getmem(ad&0xff)<<8;
699 return getmem(ad2);
700 case indy:
701 ad=getmem(pc++);
702 ad2=getmem(ad);
703 ad2|=getmem((ad+1)&0xff)<<8;
704 ad=ad2+y;
705 return getmem(ad);
706 case acc:
707 return a;
709 return 0;
712 static inline void setaddr(int mode, unsigned char val)
714 unsigned short ad,ad2;
715 switch(mode)
717 case _abs:
718 ad=getmem(pc-2);
719 ad|=256*getmem(pc-1);
720 setmem(ad,val);
721 return;
722 case absx:
723 ad=getmem(pc-2);
724 ad|=256*getmem(pc-1);
725 ad2=ad+x;
726 setmem(ad2,val);
727 return;
728 case zp:
729 ad=getmem(pc-1);
730 setmem(ad,val);
731 return;
732 case zpx:
733 ad=getmem(pc-1);
734 ad+=x;
735 setmem(ad&0xff,val);
736 return;
737 case acc:
738 a=val;
739 return;
744 static inline void putaddr(int mode, unsigned char val)
746 unsigned short ad,ad2;
747 switch(mode)
749 case _abs:
750 ad=getmem(pc++);
751 ad|=getmem(pc++)<<8;
752 setmem(ad,val);
753 return;
754 case absx:
755 ad=getmem(pc++);
756 ad|=getmem(pc++)<<8;
757 ad2=ad+x;
758 setmem(ad2,val);
759 return;
760 case absy:
761 ad=getmem(pc++);
762 ad|=getmem(pc++)<<8;
763 ad2=ad+y;
764 setmem(ad2,val);
765 return;
766 case zp:
767 ad=getmem(pc++);
768 setmem(ad,val);
769 return;
770 case zpx:
771 ad=getmem(pc++);
772 ad+=x;
773 setmem(ad&0xff,val);
774 return;
775 case zpy:
776 ad=getmem(pc++);
777 ad+=y;
778 setmem(ad&0xff,val);
779 return;
780 case indx:
781 ad=getmem(pc++);
782 ad+=x;
783 ad2=getmem(ad&0xff);
784 ad++;
785 ad2|=getmem(ad&0xff)<<8;
786 setmem(ad2,val);
787 return;
788 case indy:
789 ad=getmem(pc++);
790 ad2=getmem(ad);
791 ad2|=getmem((ad+1)&0xff)<<8;
792 ad=ad2+y;
793 setmem(ad,val);
794 return;
795 case acc:
796 a=val;
797 return;
802 static inline void setflags(int flag, int cond)
804 if (cond) p|=flag;
805 else p&=~flag;
809 static inline void push(unsigned char val)
811 setmem(0x100+s,val);
812 if (s) s--;
815 static inline unsigned char pop(void)
817 if (s<0xff) s++;
818 return getmem(0x100+s);
821 static inline void branch(int flag)
823 signed char dist;
824 dist=(signed char)getaddr(imm);
825 wval=pc+dist;
826 if (flag) pc=wval;
829 void cpuReset(void) ICODE_ATTR;
830 void cpuReset(void)
832 a=x=y=0;
833 p=0;
834 s=255;
835 pc=getaddr(0xfffc);
838 void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
839 void cpuResetTo(unsigned short npc, unsigned char na)
841 a=na;
842 x=0;
843 y=0;
844 p=0;
845 s=255;
846 pc=npc;
849 static inline void cpuParse(void)
851 unsigned char opc=getmem(pc++);
852 int cmd=opcodes[opc];
853 int addr=modes[opc];
854 int c;
855 switch (cmd)
857 case adc:
858 wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
859 setflags(FLAG_C, wval&0x100);
860 a=(unsigned char)wval;
861 setflags(FLAG_Z, !a);
862 setflags(FLAG_N, a&0x80);
863 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
864 break;
865 case _and:
866 bval=getaddr(addr);
867 a&=bval;
868 setflags(FLAG_Z, !a);
869 setflags(FLAG_N, a&0x80);
870 break;
871 case asl:
872 wval=getaddr(addr);
873 wval<<=1;
874 setaddr(addr,(unsigned char)wval);
875 setflags(FLAG_Z,!wval);
876 setflags(FLAG_N,wval&0x80);
877 setflags(FLAG_C,wval&0x100);
878 break;
879 case bcc:
880 branch(!(p&FLAG_C));
881 break;
882 case bcs:
883 branch(p&FLAG_C);
884 break;
885 case bne:
886 branch(!(p&FLAG_Z));
887 break;
888 case beq:
889 branch(p&FLAG_Z);
890 break;
891 case bpl:
892 branch(!(p&FLAG_N));
893 break;
894 case bmi:
895 branch(p&FLAG_N);
896 break;
897 case bvc:
898 branch(!(p&FLAG_V));
899 break;
900 case bvs:
901 branch(p&FLAG_V);
902 break;
903 case bit:
904 bval=getaddr(addr);
905 setflags(FLAG_Z,!(a&bval));
906 setflags(FLAG_N,bval&0x80);
907 setflags(FLAG_V,bval&0x40);
908 break;
909 case brk:
910 pc=0; /* Just quit the emulation */
911 break;
912 case clc:
913 setflags(FLAG_C,0);
914 break;
915 case cld:
916 setflags(FLAG_D,0);
917 break;
918 case cli:
919 setflags(FLAG_I,0);
920 break;
921 case clv:
922 setflags(FLAG_V,0);
923 break;
924 case cmp:
925 bval=getaddr(addr);
926 wval=(unsigned short)a-bval;
927 setflags(FLAG_Z,!wval);
928 setflags(FLAG_N,wval&0x80);
929 setflags(FLAG_C,a>=bval);
930 break;
931 case cpx:
932 bval=getaddr(addr);
933 wval=(unsigned short)x-bval;
934 setflags(FLAG_Z,!wval);
935 setflags(FLAG_N,wval&0x80);
936 setflags(FLAG_C,x>=bval);
937 break;
938 case cpy:
939 bval=getaddr(addr);
940 wval=(unsigned short)y-bval;
941 setflags(FLAG_Z,!wval);
942 setflags(FLAG_N,wval&0x80);
943 setflags(FLAG_C,y>=bval);
944 break;
945 case dec:
946 bval=getaddr(addr);
947 bval--;
948 setaddr(addr,bval);
949 setflags(FLAG_Z,!bval);
950 setflags(FLAG_N,bval&0x80);
951 break;
952 case dex:
953 x--;
954 setflags(FLAG_Z,!x);
955 setflags(FLAG_N,x&0x80);
956 break;
957 case dey:
958 y--;
959 setflags(FLAG_Z,!y);
960 setflags(FLAG_N,y&0x80);
961 break;
962 case eor:
963 bval=getaddr(addr);
964 a^=bval;
965 setflags(FLAG_Z,!a);
966 setflags(FLAG_N,a&0x80);
967 break;
968 case inc:
969 bval=getaddr(addr);
970 bval++;
971 setaddr(addr,bval);
972 setflags(FLAG_Z,!bval);
973 setflags(FLAG_N,bval&0x80);
974 break;
975 case inx:
976 x++;
977 setflags(FLAG_Z,!x);
978 setflags(FLAG_N,x&0x80);
979 break;
980 case iny:
981 y++;
982 setflags(FLAG_Z,!y);
983 setflags(FLAG_N,y&0x80);
984 break;
985 case jmp:
986 wval=getmem(pc++);
987 wval|=256*getmem(pc++);
988 switch (addr)
990 case _abs:
991 pc=wval;
992 break;
993 case ind:
994 pc=getmem(wval);
995 pc|=256*getmem(wval+1);
996 break;
998 break;
999 case jsr:
1000 push((pc+1)>>8);
1001 push((pc+1));
1002 wval=getmem(pc++);
1003 wval|=256*getmem(pc++);
1004 pc=wval;
1005 break;
1006 case lda:
1007 a=getaddr(addr);
1008 setflags(FLAG_Z,!a);
1009 setflags(FLAG_N,a&0x80);
1010 break;
1011 case ldx:
1012 x=getaddr(addr);
1013 setflags(FLAG_Z,!x);
1014 setflags(FLAG_N,x&0x80);
1015 break;
1016 case ldy:
1017 y=getaddr(addr);
1018 setflags(FLAG_Z,!y);
1019 setflags(FLAG_N,y&0x80);
1020 break;
1021 case lsr:
1022 bval=getaddr(addr); wval=(unsigned char)bval;
1023 wval>>=1;
1024 setaddr(addr,(unsigned char)wval);
1025 setflags(FLAG_Z,!wval);
1026 setflags(FLAG_N,wval&0x80);
1027 setflags(FLAG_C,bval&1);
1028 break;
1029 case _nop:
1030 break;
1031 case ora:
1032 bval=getaddr(addr);
1033 a|=bval;
1034 setflags(FLAG_Z,!a);
1035 setflags(FLAG_N,a&0x80);
1036 break;
1037 case pha:
1038 push(a);
1039 break;
1040 case php:
1041 push(p);
1042 break;
1043 case pla:
1044 a=pop();
1045 setflags(FLAG_Z,!a);
1046 setflags(FLAG_N,a&0x80);
1047 break;
1048 case plp:
1049 p=pop();
1050 break;
1051 case rol:
1052 bval=getaddr(addr);
1053 c=!!(p&FLAG_C);
1054 setflags(FLAG_C,bval&0x80);
1055 bval<<=1;
1056 bval|=c;
1057 setaddr(addr,bval);
1058 setflags(FLAG_N,bval&0x80);
1059 setflags(FLAG_Z,!bval);
1060 break;
1061 case ror:
1062 bval=getaddr(addr);
1063 c=!!(p&FLAG_C);
1064 setflags(FLAG_C,bval&1);
1065 bval>>=1;
1066 bval|=128*c;
1067 setaddr(addr,bval);
1068 setflags(FLAG_N,bval&0x80);
1069 setflags(FLAG_Z,!bval);
1070 break;
1071 case rti:
1072 /* Treat RTI like RTS */
1073 case rts:
1074 wval=pop();
1075 wval|=pop()<<8;
1076 pc=wval+1;
1077 break;
1078 case sbc:
1079 bval=getaddr(addr)^0xff;
1080 wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
1081 setflags(FLAG_C, wval&0x100);
1082 a=(unsigned char)wval;
1083 setflags(FLAG_Z, !a);
1084 setflags(FLAG_N, a>127);
1085 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
1086 break;
1087 case sec:
1088 setflags(FLAG_C,1);
1089 break;
1090 case sed:
1091 setflags(FLAG_D,1);
1092 break;
1093 case sei:
1094 setflags(FLAG_I,1);
1095 break;
1096 case sta:
1097 putaddr(addr,a);
1098 break;
1099 case stx:
1100 putaddr(addr,x);
1101 break;
1102 case sty:
1103 putaddr(addr,y);
1104 break;
1105 case tax:
1106 x=a;
1107 setflags(FLAG_Z, !x);
1108 setflags(FLAG_N, x&0x80);
1109 break;
1110 case tay:
1111 y=a;
1112 setflags(FLAG_Z, !y);
1113 setflags(FLAG_N, y&0x80);
1114 break;
1115 case tsx:
1116 x=s;
1117 setflags(FLAG_Z, !x);
1118 setflags(FLAG_N, x&0x80);
1119 break;
1120 case txa:
1121 a=x;
1122 setflags(FLAG_Z, !a);
1123 setflags(FLAG_N, a&0x80);
1124 break;
1125 case txs:
1126 s=x;
1127 break;
1128 case tya:
1129 a=y;
1130 setflags(FLAG_Z, !a);
1131 setflags(FLAG_N, a&0x80);
1132 break;
1136 void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1137 void cpuJSR(unsigned short npc, unsigned char na)
1139 a=na;
1140 x=0;
1141 y=0;
1142 p=0;
1143 s=255;
1144 pc=npc;
1145 push(0);
1146 push(0);
1148 while (pc > 1)
1149 cpuParse();
1153 void c64Init(int nSampleRate) ICODE_ATTR;
1154 void c64Init(int nSampleRate)
1156 synth_init(nSampleRate);
1157 memset(memory, 0, sizeof(memory));
1159 cpuReset();
1164 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1165 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size) ICODE_ATTR;
1166 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1167 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
1169 unsigned char *pData;
1170 unsigned char data_file_offset;
1172 pData = (unsigned char*)pSidData;
1173 data_file_offset = pData[7];
1175 *load_addr = pData[8]<<8;
1176 *load_addr|= pData[9];
1178 *init_addr = pData[10]<<8;
1179 *init_addr|= pData[11];
1181 *play_addr = pData[12]<<8;
1182 *play_addr|= pData[13];
1184 *subsongs = pData[0xf]-1;
1185 *startsong = pData[0x11]-1;
1187 *load_addr = pData[data_file_offset];
1188 *load_addr|= pData[data_file_offset+1]<<8;
1190 *speed = pData[0x15];
1192 memset(memory, 0, sizeof(memory));
1193 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1195 if (*play_addr == 0)
1197 cpuJSR(*init_addr, 0);
1198 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1201 return *load_addr;
1205 enum codec_status codec_main(void)
1207 size_t n, bytesfree;
1208 unsigned char *p;
1209 unsigned int filesize;
1211 unsigned short load_addr, init_addr, play_addr;
1212 unsigned char subSongsMax, subSong, song_speed;
1214 int nSamplesRendered = 0;
1215 int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1216 int nSamplesToRender = 0;
1218 /* Generic codec initialisation */
1219 ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512);
1220 ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*256);
1222 next_track:
1223 if (codec_init()) {
1224 return CODEC_ERROR;
1227 while (!*ci->taginfo_ready)
1228 ci->yield();
1230 codec_set_replaygain(ci->id3);
1232 /* Load SID file */
1233 p = sidfile;
1234 bytesfree=sizeof(sidfile);
1235 while ((n = ci->read_filebuf(p, bytesfree)) > 0) {
1236 p += n;
1237 bytesfree -= n;
1239 filesize = p-sidfile;
1241 if (filesize == 0)
1242 return CODEC_ERROR;
1244 c64Init(44100);
1245 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, &subSongsMax, &subSong, &song_speed, filesize);
1246 sidPoke(24, 15); /* Turn on full volume */
1247 cpuJSR(init_addr, subSong); /* Start the song initialize */
1250 /* Make use of 44.1khz */
1251 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1252 /* Sample depth is 28 bit host endian */
1253 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1254 /* Mono output */
1255 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1258 /* Set the elapsed time to the current subsong (in seconds) */
1259 ci->set_elapsed(subSong*1000);
1261 /* The main decoder loop */
1262 while (1) {
1263 ci->yield();
1264 if (ci->stop_codec || ci->new_track)
1265 break;
1267 if (ci->seek_time) {
1268 /* New time is ready in ci->seek_time */
1270 /* Start playing from scratch */
1271 c64Init(44100);
1272 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, &subSongsMax, &subSong, &song_speed, filesize);
1273 sidPoke(24, 15); /* Turn on full volume */
1274 subSong = ci->seek_time / 1000; /* Now use the current seek time in seconds as subsong */
1275 cpuJSR(init_addr, subSong); /* Start the song initialize */
1276 nSamplesToRender = 0; /* Start the rendering from scratch */
1278 ci->seek_complete();
1280 /* Set the elapsed time to the current subsong (in seconds) */
1281 ci->set_elapsed(subSong*1000);
1284 nSamplesRendered = 0;
1285 while (nSamplesRendered < CHUNK_SIZE)
1287 if (nSamplesToRender == 0)
1289 cpuJSR(play_addr, 0);
1291 /* Find out if cia timing is used and how many samples
1292 have to be calculated for each cpujsr */
1293 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
1294 if ((nRefreshCIA==0) || (song_speed == 0))
1295 nRefreshCIA = 20000;
1296 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1298 nSamplesToRender = nSamplesPerCall;
1300 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1302 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1303 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1304 nSamplesRendered = CHUNK_SIZE;
1306 else
1308 synth_render(samples+nSamplesRendered, nSamplesToRender);
1309 nSamplesRendered += nSamplesToRender;
1310 nSamplesToRender = 0;
1314 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1317 if (ci->request_next_track())
1318 goto next_track;
1320 return CODEC_OK;