Merge branch 'master' into android-test-plugins
[kugel-rb.git] / apps / codecs / sid.c
blob46c4a5408f50b01cc94d6991105a6c076527e99a
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 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
24 ****************************************************************************/
26 /*****************************
27 * kb explicitly points out that this emulation sounds crappy, though
28 * we decided to put it open source so everyone can enjoy sidmusic
29 * on rockbox
31 *****************************/
33 /*********************
34 * v1.1
35 * Added 16-04-2006: Rainer Sinsch
36 * Removed all time critical floating point operations and
37 * replaced them with quick & dirty integer calculations
39 * Added 17-04-2006: Rainer Sinsch
40 * Improved quick & dirty integer calculations for the resonant filter
41 * Improved audio quality by 4 bits
43 * v1.2
44 * Added 17-04-2006: Dave Chapman
45 * Improved file loading
47 * Added 17-04-2006: Rainer Sinsch
48 * Added sample routines
49 * Added cia timing routines
50 * Added fast forwarding capabilities
51 * Corrected bug in sid loading
53 * v1.2.1
54 * Added 04-05-2006: Rainer Sinsch
55 * Implemented Marco Alanens suggestion for subsong selection:
56 * Select the subsong by seeking: Each second represents a subsong
58 **************************/
60 #define USE_FILTER
62 #include "debug.h"
63 #include "codeclib.h"
64 #include <inttypes.h>
66 CODEC_HEADER
68 #define CHUNK_SIZE (1024*2)
70 /* This codec supports SID Files:
74 static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
76 /* Static buffer for the plain SID-File */
77 static unsigned char sidfile[0x10000];
79 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
81 #define FLAG_N 128
82 #define FLAG_V 64
83 #define FLAG_B 16
84 #define FLAG_D 8
85 #define FLAG_I 4
86 #define FLAG_Z 2
87 #define FLAG_C 1
89 #define imp 0
90 #define imm 1
91 #define _abs 2
92 #define absx 3
93 #define absy 4
94 #define zp 6
95 #define zpx 7
96 #define zpy 8
97 #define ind 9
98 #define indx 10
99 #define indy 11
100 #define acc 12
101 #define rel 13
103 enum {
104 adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, _brk, bvc, bvs, clc,
105 cld, cli, clv, cmp, cpx, cpy, dec, dex, dey, eor, inc, inx, iny, jmp,
106 jsr, lda, ldx, ldy, lsr, _nop, ora, pha, php, pla, plp, rol, ror, rti,
107 rts, sbc, sec, sed, sei, sta, stx, sty, tax, tay, tsx, txa, txs, tya,
111 /* SID register definition */
112 struct s6581 {
113 struct sidvoice {
114 unsigned short freq;
115 unsigned short pulse;
116 unsigned char wave;
117 unsigned char ad;
118 unsigned char sr;
119 } v[3];
120 unsigned char ffreqlo;
121 unsigned char ffreqhi;
122 unsigned char res_ftv;
123 unsigned char ftp_vol;
126 /* internal oscillator def */
127 struct sidosc {
128 unsigned long freq;
129 unsigned long pulse;
130 unsigned char wave;
131 unsigned char filter;
132 unsigned long attack;
133 unsigned long decay;
134 unsigned long sustain;
135 unsigned long release;
136 unsigned long counter;
137 signed long envval;
138 unsigned char envphase;
139 unsigned long noisepos;
140 unsigned long noiseval;
141 unsigned char noiseout;
144 /* internal filter def */
145 struct sidflt {
146 int freq;
147 unsigned char l_ena;
148 unsigned char b_ena;
149 unsigned char h_ena;
150 unsigned char v3ena;
151 int vol;
152 int rez;
153 int h;
154 int b;
155 int l;
158 /* ------------------------ pseudo-constants (depending on mixing freq) */
159 int mixing_frequency IDATA_ATTR;
160 unsigned long freqmul IDATA_ATTR;
161 int filtmul IDATA_ATTR;
162 unsigned long attacks [16] IDATA_ATTR;
163 unsigned long releases[16] IDATA_ATTR;
165 /* ------------------------------------------------------------ globals */
166 struct s6581 sid IDATA_ATTR;
167 struct sidosc osc[3] IDATA_ATTR;
168 struct sidflt filter IDATA_ATTR;
170 /* ------------------------------------------------------ C64 Emu Stuff */
171 unsigned char bval IDATA_ATTR;
172 unsigned short wval IDATA_ATTR;
173 /* -------------------------------------------------- Register & memory */
174 unsigned char a,x,y,s,p IDATA_ATTR;
175 unsigned short pc IDATA_ATTR;
177 unsigned char memory[65536];
179 /* ----------------------------------------- Variables for sample stuff */
180 static int sample_active IDATA_ATTR;
181 static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
182 static int fracPos IDATA_ATTR; /* Fractal position of sample */
183 static int sample_period IDATA_ATTR;
184 static int sample_repeats IDATA_ATTR;
185 static int sample_order IDATA_ATTR;
186 static int sample_nibble IDATA_ATTR;
188 static int internal_period, internal_order, internal_start, internal_end,
189 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
191 /* ---------------------------------------------------------- constants */
192 static const float attackTimes[16] ICONST_ATTR =
194 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
195 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
196 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
197 0.977715461, 2.93364701, 4.88907793, 7.82272493
199 static const float decayReleaseTimes[16] ICONST_ATTR =
201 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
202 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
203 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
206 static const int opcodes[256] ICONST_ATTR = {
207 _brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
208 bpl,ora,xxx,xxx,xxx,ora,asl,xxx,clc,ora,xxx,xxx,xxx,ora,asl,xxx,
209 jsr,_and,xxx,xxx,bit,_and,rol,xxx,plp,_and,rol,xxx,bit,_and,rol,xxx,
210 bmi,_and,xxx,xxx,xxx,_and,rol,xxx,sec,_and,xxx,xxx,xxx,_and,rol,xxx,
211 rti,eor,xxx,xxx,xxx,eor,lsr,xxx,pha,eor,lsr,xxx,jmp,eor,lsr,xxx,
212 bvc,eor,xxx,xxx,xxx,eor,lsr,xxx,cli,eor,xxx,xxx,xxx,eor,lsr,xxx,
213 rts,adc,xxx,xxx,xxx,adc,ror,xxx,pla,adc,ror,xxx,jmp,adc,ror,xxx,
214 bvs,adc,xxx,xxx,xxx,adc,ror,xxx,sei,adc,xxx,xxx,xxx,adc,ror,xxx,
215 xxx,sta,xxx,xxx,sty,sta,stx,xxx,dey,xxx,txa,xxx,sty,sta,stx,xxx,
216 bcc,sta,xxx,xxx,sty,sta,stx,xxx,tya,sta,txs,xxx,xxx,sta,xxx,xxx,
217 ldy,lda,ldx,xxx,ldy,lda,ldx,xxx,tay,lda,tax,xxx,ldy,lda,ldx,xxx,
218 bcs,lda,xxx,xxx,ldy,lda,ldx,xxx,clv,lda,tsx,xxx,ldy,lda,ldx,xxx,
219 cpy,cmp,xxx,xxx,cpy,cmp,dec,xxx,iny,cmp,dex,xxx,cpy,cmp,dec,xxx,
220 bne,cmp,xxx,xxx,xxx,cmp,dec,xxx,cld,cmp,xxx,xxx,xxx,cmp,dec,xxx,
221 cpx,sbc,xxx,xxx,cpx,sbc,inc,xxx,inx,sbc,_nop,xxx,cpx,sbc,inc,xxx,
222 beq,sbc,xxx,xxx,xxx,sbc,inc,xxx,sed,sbc,xxx,xxx,xxx,sbc,inc,xxx
226 static const int modes[256] ICONST_ATTR = {
227 imp,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 _abs,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,_abs,_abs,_abs,xxx,
232 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
233 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,ind,_abs,_abs,xxx,
234 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
235 imm,indx,xxx,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,xxx,absx,absx,xxx,
237 imm,indx,imm,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
238 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,absx,absx,absy,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,
241 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
242 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx
245 /* Routines for quick & dirty float calculation */
247 static inline int quickfloat_ConvertFromInt(int i)
249 return (i<<16);
251 static inline int quickfloat_ConvertFromFloat(float f)
253 return (int)(f*(1<<16));
255 static inline int quickfloat_Multiply(int a, int b)
257 return (a>>8)*(b>>8);
259 static inline int quickfloat_ConvertToInt(int i)
261 return (i>>16);
264 /* Get the bit from an unsigned long at a specified position */
265 static inline unsigned char get_bit(unsigned long val, unsigned char b)
267 return (unsigned char) ((val >> b) & 1);
271 static inline int GenerateDigi(int sIn)
273 static int sample = 0;
275 if (!sample_active) return(sIn);
277 if ((sample_position < sample_end) && (sample_position >= sample_start))
279 sIn += sample;
281 fracPos += 985248/sample_period;
283 if (fracPos > mixing_frequency)
285 fracPos%=mixing_frequency;
287 // N�hstes Samples holen
288 if (sample_order == 0) {
289 sample_nibble++; // Nähstes Sample-Nibble
290 if (sample_nibble==2) {
291 sample_nibble = 0;
292 sample_position++;
295 else {
296 sample_nibble--;
297 if (sample_nibble < 0) {
298 sample_nibble=1;
299 sample_position++;
302 if (sample_repeats)
304 if (sample_position > sample_end)
306 sample_repeats--;
307 sample_position = sample_repeat_start;
309 else sample_active = 0;
312 sample = memory[sample_position&0xffff];
313 if (sample_nibble==1) // Hi-Nibble holen?
314 sample = (sample & 0xf0)>>4;
315 else sample = sample & 0x0f;
317 sample -= 7;
318 sample <<= 10;
322 return (sIn);
325 /* ------------------------------------------------------------- synthesis
326 initialize SID and frequency dependant values */
327 void synth_init(unsigned long mixfrq) ICODE_ATTR;
328 void synth_init(unsigned long mixfrq)
330 int i;
331 mixing_frequency = mixfrq;
332 fracPos = 0;
333 freqmul = 15872000 / mixfrq;
334 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
335 for (i=0;i<16;i++) {
336 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
337 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
339 memset(&sid,0,sizeof(sid));
340 memset(osc,0,sizeof(osc));
341 memset(&filter,0,sizeof(filter));
342 osc[0].noiseval = 0xffffff;
343 osc[1].noiseval = 0xffffff;
344 osc[2].noiseval = 0xffffff;
347 /* render a buffer of n samples with the actual register contents */
348 void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
349 void synth_render (int32_t *buffer, unsigned long len)
351 unsigned long bp;
352 /* step 1: convert the not easily processable sid registers into some
353 more convenient and fast values (makes the thing much faster
354 if you process more than 1 sample value at once) */
355 unsigned char v;
356 for (v=0;v<3;v++) {
357 osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
358 osc[v].filter = get_bit(sid.res_ftv,v);
359 osc[v].attack = attacks[sid.v[v].ad >> 4];
360 osc[v].decay = releases[sid.v[v].ad & 0xf];
361 osc[v].sustain = sid.v[v].sr & 0xf0;
362 osc[v].release = releases[sid.v[v].sr & 0xf];
363 osc[v].wave = sid.v[v].wave;
364 osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
367 #ifdef USE_FILTER
368 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
370 if (filter.freq>quickfloat_ConvertFromInt(1))
371 filter.freq=quickfloat_ConvertFromInt(1);
372 /* the above line isnt correct at all - the problem is that the filter
373 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
374 for 32KHz and lower - well, but sound quality is bad enough then to
375 neglect the fact that the filter doesnt come that high ;) */
376 filter.l_ena = get_bit(sid.ftp_vol,4);
377 filter.b_ena = get_bit(sid.ftp_vol,5);
378 filter.h_ena = get_bit(sid.ftp_vol,6);
379 filter.v3ena = !get_bit(sid.ftp_vol,7);
380 filter.vol = (sid.ftp_vol & 0xf);
381 filter.rez = quickfloat_ConvertFromFloat(1.2f) -
382 quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
384 /* We precalculate part of the quick float operation, saves time in loop later */
385 filter.rez>>=8;
386 #endif
389 /* now render the buffer */
390 for (bp=0;bp<len;bp++) {
391 #ifdef USE_FILTER
392 int outo=0;
393 #endif
394 int outf=0;
395 /* step 2 : generate the two output signals (for filtered and non-
396 filtered) from the osc/eg sections */
397 for (v=0;v<3;v++) {
398 /* update wave counter */
399 osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
400 /* reset counter / noise generator if reset get_bit set */
401 if (osc[v].wave & 0x08) {
402 osc[v].counter = 0;
403 osc[v].noisepos = 0;
404 osc[v].noiseval = 0xffffff;
406 unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
407 /* sync oscillator to refosc if sync bit set */
408 if (osc[v].wave & 0x02)
409 if (osc[refosc].counter < osc[refosc].freq)
410 osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
411 /* generate waveforms with really simple algorithms */
412 unsigned char triout = (unsigned char) (osc[v].counter>>19);
413 if (osc[v].counter>>27)
414 triout^=0xff;
415 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
416 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
418 /* generate noise waveform exactly as the SID does. */
419 if (osc[v].noisepos!=(osc[v].counter>>23))
421 osc[v].noisepos = osc[v].counter >> 23;
422 osc[v].noiseval = (osc[v].noiseval << 1) |
423 (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
424 osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
425 (get_bit(osc[v].noiseval,20) << 6) |
426 (get_bit(osc[v].noiseval,16) << 5) |
427 (get_bit(osc[v].noiseval,13) << 4) |
428 (get_bit(osc[v].noiseval,11) << 3) |
429 (get_bit(osc[v].noiseval, 7) << 2) |
430 (get_bit(osc[v].noiseval, 4) << 1) |
431 (get_bit(osc[v].noiseval, 2) << 0);
433 unsigned char nseout = osc[v].noiseout;
435 /* modulate triangle wave if ringmod bit set */
436 if (osc[v].wave & 0x04)
437 if (osc[refosc].counter < 0x8000000)
438 triout ^= 0xff;
440 /* now mix the oscillators with an AND operation as stated in
441 the SID's reference manual - even if this is completely wrong.
442 well, at least, the $30 and $70 waveform sounds correct and there's
443 no real solution to do $50 and $60, so who cares. */
445 unsigned char outv=0xFF;
446 if (osc[v].wave & 0x10) outv &= triout;
447 if (osc[v].wave & 0x20) outv &= sawout;
448 if (osc[v].wave & 0x40) outv &= plsout;
449 if (osc[v].wave & 0x80) outv &= nseout;
451 /* so now process the volume according to the phase and adsr values */
452 switch (osc[v].envphase) {
453 case 0 : { /* Phase 0 : Attack */
454 osc[v].envval+=osc[v].attack;
455 if (osc[v].envval >= 0xFFFFFF)
457 osc[v].envval = 0xFFFFFF;
458 osc[v].envphase = 1;
460 break;
462 case 1 : { /* Phase 1 : Decay */
463 osc[v].envval-=osc[v].decay;
464 if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
466 osc[v].envval = osc[v].sustain<<16;
467 osc[v].envphase = 2;
469 break;
471 case 2 : { /* Phase 2 : Sustain */
472 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
474 osc[v].envphase = 1;
476 /* :) yes, thats exactly how the SID works. and maybe
477 a music routine out there supports this, so better
478 let it in, thanks :) */
479 break;
481 case 3 : { /* Phase 3 : Release */
482 osc[v].envval-=osc[v].release;
483 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
485 /* the volume offset is because the SID does not
486 completely silence the voices when it should. most
487 emulators do so though and thats the main reason
488 why the sound of emulators is too, err... emulated :) */
489 break;
493 #ifdef USE_FILTER
495 /* now route the voice output to either the non-filtered or the
496 filtered channel and dont forget to blank out osc3 if desired */
498 if (v<2 || filter.v3ena)
500 if (osc[v].filter)
501 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
502 else
503 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
505 #endif
506 #ifndef USE_FILTER
507 /* Don't use filters, just mix all voices together */
508 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
509 #endif
513 #ifdef USE_FILTER
514 /* step 3
515 * so, now theres finally time to apply the multi-mode resonant filter
516 * to the signal. The easiest thing ist just modelling a real electronic
517 * filter circuit instead of fiddling around with complex IIRs or even
518 * FIRs ...
519 * it sounds as good as them or maybe better and needs only 3 MULs and
520 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
521 * Mage messed the whole thing completely up - as the rest of the
522 * emulator.
523 * This filter sounds a lot like the 8580, as the low-quality, dirty
524 * sound of the 6581 is uuh too hard to achieve :) */
526 filter.h = quickfloat_ConvertFromInt(outf) - (filter.b>>8)*filter.rez - filter.l;
527 filter.b += quickfloat_Multiply(filter.freq, filter.h);
528 filter.l += quickfloat_Multiply(filter.freq, filter.b);
530 outf = 0;
532 if (filter.l_ena) outf+=quickfloat_ConvertToInt(filter.l);
533 if (filter.b_ena) outf+=quickfloat_ConvertToInt(filter.b);
534 if (filter.h_ena) outf+=quickfloat_ConvertToInt(filter.h);
536 int final_sample = (filter.vol*(outo+outf));
537 *(buffer+bp)= GenerateDigi(final_sample)<<13;
538 #endif
539 #ifndef USE_FILTER
540 *(buffer+bp) = GenerateDigi(outf)<<3;
541 #endif
548 * C64 Mem Routines
550 static inline unsigned char getmem(unsigned short addr)
552 return memory[addr];
555 static inline void setmem(unsigned short addr, unsigned char value)
557 if ((addr&0xfc00)==0xd400)
559 sidPoke(addr&0x1f,value);
560 /* New SID-Register */
561 if (addr > 0xd418)
563 switch (addr)
565 case 0xd41f: /* Start-Hi */
566 internal_start = (internal_start&0x00ff) | (value<<8); break;
567 case 0xd41e: /* Start-Lo */
568 internal_start = (internal_start&0xff00) | (value); break;
569 case 0xd47f: /* Repeat-Hi */
570 internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
571 case 0xd47e: /* Repeat-Lo */
572 internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
573 case 0xd43e: /* End-Hi */
574 internal_end = (internal_end&0x00ff) | (value<<8); break;
575 case 0xd43d: /* End-Lo */
576 internal_end = (internal_end&0xff00) | (value); break;
577 case 0xd43f: /* Loop-Size */
578 internal_repeat_times = value; break;
579 case 0xd45e: /* Period-Hi */
580 internal_period = (internal_period&0x00ff) | (value<<8); break;
581 case 0xd45d: /* Period-Lo */
582 internal_period = (internal_period&0xff00) | (value); break;
583 case 0xd47d: /* Sample Order */
584 internal_order = value; break;
585 case 0xd45f: /* Sample Add */
586 internal_add = value; break;
587 case 0xd41d: /* Start sampling */
588 sample_repeats = internal_repeat_times;
589 sample_position = internal_start;
590 sample_start = internal_start;
591 sample_end = internal_end;
592 sample_repeat_start = internal_repeat_start;
593 sample_period = internal_period;
594 sample_order = internal_order;
595 switch (value)
597 case 0xfd: sample_active = 0; break;
598 case 0xfe:
599 case 0xff: sample_active = 1; break;
600 default: return;
602 break;
606 else memory[addr]=value;
610 * Poke a value into the sid register
612 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
613 void sidPoke(int reg, unsigned char val)
615 int voice=0;
617 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
618 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
620 switch (reg) {
621 case 0: { /* Set frequency: Low byte */
622 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
623 break;
625 case 1: { /* Set frequency: High byte */
626 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
627 break;
629 case 2: { /* Set pulse width: Low byte */
630 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
631 break;
633 case 3: { /* Set pulse width: High byte */
634 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
635 break;
637 case 4: { sid.v[voice].wave = val;
638 /* Directly look at GATE-Bit!
639 * a change may happen twice or more often during one cpujsr
640 * Put the Envelope Generator into attack or release phase if desired
642 if ((val & 0x01) == 0) osc[voice].envphase=3;
643 else if (osc[voice].envphase==3) osc[voice].envphase=0;
644 break;
647 case 5: { sid.v[voice].ad = val; break;}
648 case 6: { sid.v[voice].sr = val; break;}
650 case 21: { sid.ffreqlo = val; break; }
651 case 22: { sid.ffreqhi = val; break; }
652 case 23: { sid.res_ftv = val; break; }
653 case 24: { sid.ftp_vol = val; break;}
655 return;
658 static inline unsigned char getaddr(int mode)
660 unsigned short ad,ad2;
661 switch(mode)
663 case imp:
664 return 0;
665 case imm:
666 return getmem(pc++);
667 case _abs:
668 ad=getmem(pc++);
669 ad|=256*getmem(pc++);
670 return getmem(ad);
671 case absx:
672 ad=getmem(pc++);
673 ad|=256*getmem(pc++);
674 ad2=ad+x;
675 return getmem(ad2);
676 case absy:
677 ad=getmem(pc++);
678 ad|=256*getmem(pc++);
679 ad2=ad+y;
680 return getmem(ad2);
681 case zp:
682 ad=getmem(pc++);
683 return getmem(ad);
684 case zpx:
685 ad=getmem(pc++);
686 ad+=x;
687 return getmem(ad&0xff);
688 case zpy:
689 ad=getmem(pc++);
690 ad+=y;
691 return getmem(ad&0xff);
692 case indx:
693 ad=getmem(pc++);
694 ad+=x;
695 ad2=getmem(ad&0xff);
696 ad++;
697 ad2|=getmem(ad&0xff)<<8;
698 return getmem(ad2);
699 case indy:
700 ad=getmem(pc++);
701 ad2=getmem(ad);
702 ad2|=getmem((ad+1)&0xff)<<8;
703 ad=ad2+y;
704 return getmem(ad);
705 case acc:
706 return a;
708 return 0;
711 static inline void setaddr(int mode, unsigned char val)
713 unsigned short ad,ad2;
714 switch(mode)
716 case _abs:
717 ad=getmem(pc-2);
718 ad|=256*getmem(pc-1);
719 setmem(ad,val);
720 return;
721 case absx:
722 ad=getmem(pc-2);
723 ad|=256*getmem(pc-1);
724 ad2=ad+x;
725 setmem(ad2,val);
726 return;
727 case zp:
728 ad=getmem(pc-1);
729 setmem(ad,val);
730 return;
731 case zpx:
732 ad=getmem(pc-1);
733 ad+=x;
734 setmem(ad&0xff,val);
735 return;
736 case acc:
737 a=val;
738 return;
743 static inline void putaddr(int mode, unsigned char val)
745 unsigned short ad,ad2;
746 switch(mode)
748 case _abs:
749 ad=getmem(pc++);
750 ad|=getmem(pc++)<<8;
751 setmem(ad,val);
752 return;
753 case absx:
754 ad=getmem(pc++);
755 ad|=getmem(pc++)<<8;
756 ad2=ad+x;
757 setmem(ad2,val);
758 return;
759 case absy:
760 ad=getmem(pc++);
761 ad|=getmem(pc++)<<8;
762 ad2=ad+y;
763 setmem(ad2,val);
764 return;
765 case zp:
766 ad=getmem(pc++);
767 setmem(ad,val);
768 return;
769 case zpx:
770 ad=getmem(pc++);
771 ad+=x;
772 setmem(ad&0xff,val);
773 return;
774 case zpy:
775 ad=getmem(pc++);
776 ad+=y;
777 setmem(ad&0xff,val);
778 return;
779 case indx:
780 ad=getmem(pc++);
781 ad+=x;
782 ad2=getmem(ad&0xff);
783 ad++;
784 ad2|=getmem(ad&0xff)<<8;
785 setmem(ad2,val);
786 return;
787 case indy:
788 ad=getmem(pc++);
789 ad2=getmem(ad);
790 ad2|=getmem((ad+1)&0xff)<<8;
791 ad=ad2+y;
792 setmem(ad,val);
793 return;
794 case acc:
795 a=val;
796 return;
801 static inline void setflags(int flag, int cond)
803 if (cond) p|=flag;
804 else p&=~flag;
808 static inline void push(unsigned char val)
810 setmem(0x100+s,val);
811 if (s) s--;
814 static inline unsigned char pop(void)
816 if (s<0xff) s++;
817 return getmem(0x100+s);
820 static inline void branch(int flag)
822 signed char dist;
823 dist=(signed char)getaddr(imm);
824 wval=pc+dist;
825 if (flag) pc=wval;
828 void cpuReset(void) ICODE_ATTR;
829 void cpuReset(void)
831 a=x=y=0;
832 p=0;
833 s=255;
834 pc=getaddr(0xfffc);
837 void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
838 void cpuResetTo(unsigned short npc, unsigned char na)
840 a=na;
841 x=0;
842 y=0;
843 p=0;
844 s=255;
845 pc=npc;
848 static inline void cpuParse(void)
850 unsigned char opc=getmem(pc++);
851 int cmd=opcodes[opc];
852 int addr=modes[opc];
853 int c;
854 switch (cmd)
856 case adc:
857 wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
858 setflags(FLAG_C, wval&0x100);
859 a=(unsigned char)wval;
860 setflags(FLAG_Z, !a);
861 setflags(FLAG_N, a&0x80);
862 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
863 break;
864 case _and:
865 bval=getaddr(addr);
866 a&=bval;
867 setflags(FLAG_Z, !a);
868 setflags(FLAG_N, a&0x80);
869 break;
870 case asl:
871 wval=getaddr(addr);
872 wval<<=1;
873 setaddr(addr,(unsigned char)wval);
874 setflags(FLAG_Z,!wval);
875 setflags(FLAG_N,wval&0x80);
876 setflags(FLAG_C,wval&0x100);
877 break;
878 case bcc:
879 branch(!(p&FLAG_C));
880 break;
881 case bcs:
882 branch(p&FLAG_C);
883 break;
884 case bne:
885 branch(!(p&FLAG_Z));
886 break;
887 case beq:
888 branch(p&FLAG_Z);
889 break;
890 case bpl:
891 branch(!(p&FLAG_N));
892 break;
893 case bmi:
894 branch(p&FLAG_N);
895 break;
896 case bvc:
897 branch(!(p&FLAG_V));
898 break;
899 case bvs:
900 branch(p&FLAG_V);
901 break;
902 case bit:
903 bval=getaddr(addr);
904 setflags(FLAG_Z,!(a&bval));
905 setflags(FLAG_N,bval&0x80);
906 setflags(FLAG_V,bval&0x40);
907 break;
908 case _brk:
909 pc=0; /* Just quit the emulation */
910 break;
911 case clc:
912 setflags(FLAG_C,0);
913 break;
914 case cld:
915 setflags(FLAG_D,0);
916 break;
917 case cli:
918 setflags(FLAG_I,0);
919 break;
920 case clv:
921 setflags(FLAG_V,0);
922 break;
923 case cmp:
924 bval=getaddr(addr);
925 wval=(unsigned short)a-bval;
926 setflags(FLAG_Z,!wval);
927 setflags(FLAG_N,wval&0x80);
928 setflags(FLAG_C,a>=bval);
929 break;
930 case cpx:
931 bval=getaddr(addr);
932 wval=(unsigned short)x-bval;
933 setflags(FLAG_Z,!wval);
934 setflags(FLAG_N,wval&0x80);
935 setflags(FLAG_C,x>=bval);
936 break;
937 case cpy:
938 bval=getaddr(addr);
939 wval=(unsigned short)y-bval;
940 setflags(FLAG_Z,!wval);
941 setflags(FLAG_N,wval&0x80);
942 setflags(FLAG_C,y>=bval);
943 break;
944 case dec:
945 bval=getaddr(addr);
946 bval--;
947 setaddr(addr,bval);
948 setflags(FLAG_Z,!bval);
949 setflags(FLAG_N,bval&0x80);
950 break;
951 case dex:
952 x--;
953 setflags(FLAG_Z,!x);
954 setflags(FLAG_N,x&0x80);
955 break;
956 case dey:
957 y--;
958 setflags(FLAG_Z,!y);
959 setflags(FLAG_N,y&0x80);
960 break;
961 case eor:
962 bval=getaddr(addr);
963 a^=bval;
964 setflags(FLAG_Z,!a);
965 setflags(FLAG_N,a&0x80);
966 break;
967 case inc:
968 bval=getaddr(addr);
969 bval++;
970 setaddr(addr,bval);
971 setflags(FLAG_Z,!bval);
972 setflags(FLAG_N,bval&0x80);
973 break;
974 case inx:
975 x++;
976 setflags(FLAG_Z,!x);
977 setflags(FLAG_N,x&0x80);
978 break;
979 case iny:
980 y++;
981 setflags(FLAG_Z,!y);
982 setflags(FLAG_N,y&0x80);
983 break;
984 case jmp:
985 wval=getmem(pc++);
986 wval|=256*getmem(pc++);
987 switch (addr)
989 case _abs:
990 pc=wval;
991 break;
992 case ind:
993 pc=getmem(wval);
994 pc|=256*getmem(wval+1);
995 break;
997 break;
998 case jsr:
999 push((pc+1)>>8);
1000 push((pc+1));
1001 wval=getmem(pc++);
1002 wval|=256*getmem(pc++);
1003 pc=wval;
1004 break;
1005 case lda:
1006 a=getaddr(addr);
1007 setflags(FLAG_Z,!a);
1008 setflags(FLAG_N,a&0x80);
1009 break;
1010 case ldx:
1011 x=getaddr(addr);
1012 setflags(FLAG_Z,!x);
1013 setflags(FLAG_N,x&0x80);
1014 break;
1015 case ldy:
1016 y=getaddr(addr);
1017 setflags(FLAG_Z,!y);
1018 setflags(FLAG_N,y&0x80);
1019 break;
1020 case lsr:
1021 bval=getaddr(addr); wval=(unsigned char)bval;
1022 wval>>=1;
1023 setaddr(addr,(unsigned char)wval);
1024 setflags(FLAG_Z,!wval);
1025 setflags(FLAG_N,wval&0x80);
1026 setflags(FLAG_C,bval&1);
1027 break;
1028 case _nop:
1029 break;
1030 case ora:
1031 bval=getaddr(addr);
1032 a|=bval;
1033 setflags(FLAG_Z,!a);
1034 setflags(FLAG_N,a&0x80);
1035 break;
1036 case pha:
1037 push(a);
1038 break;
1039 case php:
1040 push(p);
1041 break;
1042 case pla:
1043 a=pop();
1044 setflags(FLAG_Z,!a);
1045 setflags(FLAG_N,a&0x80);
1046 break;
1047 case plp:
1048 p=pop();
1049 break;
1050 case rol:
1051 bval=getaddr(addr);
1052 c=!!(p&FLAG_C);
1053 setflags(FLAG_C,bval&0x80);
1054 bval<<=1;
1055 bval|=c;
1056 setaddr(addr,bval);
1057 setflags(FLAG_N,bval&0x80);
1058 setflags(FLAG_Z,!bval);
1059 break;
1060 case ror:
1061 bval=getaddr(addr);
1062 c=!!(p&FLAG_C);
1063 setflags(FLAG_C,bval&1);
1064 bval>>=1;
1065 bval|=128*c;
1066 setaddr(addr,bval);
1067 setflags(FLAG_N,bval&0x80);
1068 setflags(FLAG_Z,!bval);
1069 break;
1070 case rti:
1071 /* Treat RTI like RTS */
1072 case rts:
1073 wval=pop();
1074 wval|=pop()<<8;
1075 pc=wval+1;
1076 break;
1077 case sbc:
1078 bval=getaddr(addr)^0xff;
1079 wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
1080 setflags(FLAG_C, wval&0x100);
1081 a=(unsigned char)wval;
1082 setflags(FLAG_Z, !a);
1083 setflags(FLAG_N, a>127);
1084 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
1085 break;
1086 case sec:
1087 setflags(FLAG_C,1);
1088 break;
1089 case sed:
1090 setflags(FLAG_D,1);
1091 break;
1092 case sei:
1093 setflags(FLAG_I,1);
1094 break;
1095 case sta:
1096 putaddr(addr,a);
1097 break;
1098 case stx:
1099 putaddr(addr,x);
1100 break;
1101 case sty:
1102 putaddr(addr,y);
1103 break;
1104 case tax:
1105 x=a;
1106 setflags(FLAG_Z, !x);
1107 setflags(FLAG_N, x&0x80);
1108 break;
1109 case tay:
1110 y=a;
1111 setflags(FLAG_Z, !y);
1112 setflags(FLAG_N, y&0x80);
1113 break;
1114 case tsx:
1115 x=s;
1116 setflags(FLAG_Z, !x);
1117 setflags(FLAG_N, x&0x80);
1118 break;
1119 case txa:
1120 a=x;
1121 setflags(FLAG_Z, !a);
1122 setflags(FLAG_N, a&0x80);
1123 break;
1124 case txs:
1125 s=x;
1126 break;
1127 case tya:
1128 a=y;
1129 setflags(FLAG_Z, !a);
1130 setflags(FLAG_N, a&0x80);
1131 break;
1135 void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1136 void cpuJSR(unsigned short npc, unsigned char na)
1138 a=na;
1139 x=0;
1140 y=0;
1141 p=0;
1142 s=255;
1143 pc=npc;
1144 push(0);
1145 push(0);
1147 while (pc > 1)
1148 cpuParse();
1152 void c64Init(int nSampleRate) ICODE_ATTR;
1153 void c64Init(int nSampleRate)
1155 synth_init(nSampleRate);
1156 memset(memory, 0, sizeof(memory));
1158 cpuReset();
1163 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1164 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size) ICODE_ATTR;
1165 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1166 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
1168 unsigned char *pData;
1169 unsigned char data_file_offset;
1171 pData = (unsigned char*)pSidData;
1172 data_file_offset = pData[7];
1174 *load_addr = pData[8]<<8;
1175 *load_addr|= pData[9];
1177 *init_addr = pData[10]<<8;
1178 *init_addr|= pData[11];
1180 *play_addr = pData[12]<<8;
1181 *play_addr|= pData[13];
1183 *subsongs = pData[0xf]-1;
1184 *startsong = pData[0x11]-1;
1186 *load_addr = pData[data_file_offset];
1187 *load_addr|= pData[data_file_offset+1]<<8;
1189 *speed = pData[0x15];
1191 memset(memory, 0, sizeof(memory));
1192 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1194 if (*play_addr == 0)
1196 cpuJSR(*init_addr, 0);
1197 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1200 return *load_addr;
1203 static int nSamplesRendered = 0;
1204 static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1205 static int nSamplesToRender = 0;
1207 /* this is the codec entry point */
1208 enum codec_status codec_main(enum codec_entry_call_reason reason)
1210 if (reason == CODEC_LOAD) {
1211 /* Make use of 44.1khz */
1212 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1213 /* Sample depth is 28 bit host endian */
1214 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1215 /* Mono output */
1216 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1219 return CODEC_OK;
1222 /* this is called for each file to process */
1223 enum codec_status codec_run(void)
1225 unsigned int filesize;
1226 unsigned short load_addr, init_addr, play_addr;
1227 unsigned char subSongsMax, subSong, song_speed;
1228 intptr_t param;
1230 if (codec_init()) {
1231 return CODEC_ERROR;
1234 codec_set_replaygain(ci->id3);
1236 /* Load SID file the read_filebuf callback will return the full requested
1237 * size if at all possible, so there is no need to loop */
1238 ci->seek_buffer(0);
1239 filesize = ci->read_filebuf(sidfile, sizeof(sidfile));
1241 if (filesize == 0) {
1242 return CODEC_ERROR;
1245 c64Init(44100);
1246 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1247 &subSongsMax, &subSong, &song_speed, filesize);
1248 sidPoke(24, 15); /* Turn on full volume */
1249 cpuJSR(init_addr, subSong); /* Start the song initialize */
1252 /* Set the elapsed time to the current subsong (in seconds) */
1253 ci->set_elapsed(subSong*1000);
1255 /* The main decoder loop */
1256 while (1) {
1257 enum codec_command_action action = ci->get_command(&param);
1259 if (action == CODEC_ACTION_HALT)
1260 break;
1262 if (action == CODEC_ACTION_SEEK_TIME) {
1263 /* New time is ready in param */
1265 /* Start playing from scratch */
1266 c64Init(44100);
1267 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1268 &subSongsMax, &subSong, &song_speed, filesize);
1269 sidPoke(24, 15); /* Turn on full volume */
1270 subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
1271 cpuJSR(init_addr, subSong); /* Start the song initialize */
1272 nSamplesToRender = 0; /* Start the rendering from scratch */
1274 /* Set the elapsed time to the current subsong (in seconds) */
1275 ci->seek_complete();
1276 ci->set_elapsed(subSong*1000);
1279 nSamplesRendered = 0;
1280 while (nSamplesRendered < CHUNK_SIZE)
1282 if (nSamplesToRender == 0)
1284 cpuJSR(play_addr, 0);
1286 /* Find out if cia timing is used and how many samples
1287 have to be calculated for each cpujsr */
1288 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
1289 if ((nRefreshCIA==0) || (song_speed == 0))
1290 nRefreshCIA = 20000;
1291 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1293 nSamplesToRender = nSamplesPerCall;
1295 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1297 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1298 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1299 nSamplesRendered = CHUNK_SIZE;
1301 else
1303 synth_render(samples+nSamplesRendered, nSamplesToRender);
1304 nSamplesRendered += nSamplesToRender;
1305 nSamplesToRender = 0;
1309 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1312 return CODEC_OK;