Fix %Sp expansion in wps
[kugel-rb.git] / apps / codecs / sid.c
blobc00aa221424e6d9ddb16b02a5d0a00772b730d29
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 last_sample = 0;
274 static int sample = 0;
276 if (!sample_active) return(sIn);
278 if ((sample_position < sample_end) && (sample_position >= sample_start))
280 sIn += sample;
282 fracPos += 985248/sample_period;
284 if (fracPos > mixing_frequency)
286 fracPos%=mixing_frequency;
288 last_sample = sample;
290 // N�hstes Samples holen
291 if (sample_order == 0) {
292 sample_nibble++; // Nähstes Sample-Nibble
293 if (sample_nibble==2) {
294 sample_nibble = 0;
295 sample_position++;
298 else {
299 sample_nibble--;
300 if (sample_nibble < 0) {
301 sample_nibble=1;
302 sample_position++;
305 if (sample_repeats)
307 if (sample_position > sample_end)
309 sample_repeats--;
310 sample_position = sample_repeat_start;
312 else sample_active = 0;
315 sample = memory[sample_position&0xffff];
316 if (sample_nibble==1) // Hi-Nibble holen?
317 sample = (sample & 0xf0)>>4;
318 else sample = sample & 0x0f;
320 sample -= 7;
321 sample <<= 10;
325 return (sIn);
328 /* ------------------------------------------------------------- synthesis
329 initialize SID and frequency dependant values */
330 void synth_init(unsigned long mixfrq) ICODE_ATTR;
331 void synth_init(unsigned long mixfrq)
333 int i;
334 mixing_frequency = mixfrq;
335 fracPos = 0;
336 freqmul = 15872000 / mixfrq;
337 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
338 for (i=0;i<16;i++) {
339 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
340 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
342 memset(&sid,0,sizeof(sid));
343 memset(osc,0,sizeof(osc));
344 memset(&filter,0,sizeof(filter));
345 osc[0].noiseval = 0xffffff;
346 osc[1].noiseval = 0xffffff;
347 osc[2].noiseval = 0xffffff;
350 /* render a buffer of n samples with the actual register contents */
351 void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
352 void synth_render (int32_t *buffer, unsigned long len)
354 unsigned long bp;
355 /* step 1: convert the not easily processable sid registers into some
356 more convenient and fast values (makes the thing much faster
357 if you process more than 1 sample value at once) */
358 unsigned char v;
359 for (v=0;v<3;v++) {
360 osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
361 osc[v].filter = get_bit(sid.res_ftv,v);
362 osc[v].attack = attacks[sid.v[v].ad >> 4];
363 osc[v].decay = releases[sid.v[v].ad & 0xf];
364 osc[v].sustain = sid.v[v].sr & 0xf0;
365 osc[v].release = releases[sid.v[v].sr & 0xf];
366 osc[v].wave = sid.v[v].wave;
367 osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
370 #ifdef USE_FILTER
371 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
373 if (filter.freq>quickfloat_ConvertFromInt(1))
374 filter.freq=quickfloat_ConvertFromInt(1);
375 /* the above line isnt correct at all - the problem is that the filter
376 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
377 for 32KHz and lower - well, but sound quality is bad enough then to
378 neglect the fact that the filter doesnt come that high ;) */
379 filter.l_ena = get_bit(sid.ftp_vol,4);
380 filter.b_ena = get_bit(sid.ftp_vol,5);
381 filter.h_ena = get_bit(sid.ftp_vol,6);
382 filter.v3ena = !get_bit(sid.ftp_vol,7);
383 filter.vol = (sid.ftp_vol & 0xf);
384 filter.rez = quickfloat_ConvertFromFloat(1.2f) -
385 quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
387 /* We precalculate part of the quick float operation, saves time in loop later */
388 filter.rez>>=8;
389 #endif
392 /* now render the buffer */
393 for (bp=0;bp<len;bp++) {
394 #ifdef USE_FILTER
395 int outo=0;
396 #endif
397 int outf=0;
398 /* step 2 : generate the two output signals (for filtered and non-
399 filtered) from the osc/eg sections */
400 for (v=0;v<3;v++) {
401 /* update wave counter */
402 osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
403 /* reset counter / noise generator if reset get_bit set */
404 if (osc[v].wave & 0x08) {
405 osc[v].counter = 0;
406 osc[v].noisepos = 0;
407 osc[v].noiseval = 0xffffff;
409 unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
410 /* sync oscillator to refosc if sync bit set */
411 if (osc[v].wave & 0x02)
412 if (osc[refosc].counter < osc[refosc].freq)
413 osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
414 /* generate waveforms with really simple algorithms */
415 unsigned char triout = (unsigned char) (osc[v].counter>>19);
416 if (osc[v].counter>>27)
417 triout^=0xff;
418 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
419 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
421 /* generate noise waveform exactly as the SID does. */
422 if (osc[v].noisepos!=(osc[v].counter>>23))
424 osc[v].noisepos = osc[v].counter >> 23;
425 osc[v].noiseval = (osc[v].noiseval << 1) |
426 (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
427 osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
428 (get_bit(osc[v].noiseval,20) << 6) |
429 (get_bit(osc[v].noiseval,16) << 5) |
430 (get_bit(osc[v].noiseval,13) << 4) |
431 (get_bit(osc[v].noiseval,11) << 3) |
432 (get_bit(osc[v].noiseval, 7) << 2) |
433 (get_bit(osc[v].noiseval, 4) << 1) |
434 (get_bit(osc[v].noiseval, 2) << 0);
436 unsigned char nseout = osc[v].noiseout;
438 /* modulate triangle wave if ringmod bit set */
439 if (osc[v].wave & 0x04)
440 if (osc[refosc].counter < 0x8000000)
441 triout ^= 0xff;
443 /* now mix the oscillators with an AND operation as stated in
444 the SID's reference manual - even if this is completely wrong.
445 well, at least, the $30 and $70 waveform sounds correct and there's
446 no real solution to do $50 and $60, so who cares. */
448 unsigned char outv=0xFF;
449 if (osc[v].wave & 0x10) outv &= triout;
450 if (osc[v].wave & 0x20) outv &= sawout;
451 if (osc[v].wave & 0x40) outv &= plsout;
452 if (osc[v].wave & 0x80) outv &= nseout;
454 /* so now process the volume according to the phase and adsr values */
455 switch (osc[v].envphase) {
456 case 0 : { /* Phase 0 : Attack */
457 osc[v].envval+=osc[v].attack;
458 if (osc[v].envval >= 0xFFFFFF)
460 osc[v].envval = 0xFFFFFF;
461 osc[v].envphase = 1;
463 break;
465 case 1 : { /* Phase 1 : Decay */
466 osc[v].envval-=osc[v].decay;
467 if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
469 osc[v].envval = osc[v].sustain<<16;
470 osc[v].envphase = 2;
472 break;
474 case 2 : { /* Phase 2 : Sustain */
475 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
477 osc[v].envphase = 1;
479 /* :) yes, thats exactly how the SID works. and maybe
480 a music routine out there supports this, so better
481 let it in, thanks :) */
482 break;
484 case 3 : { /* Phase 3 : Release */
485 osc[v].envval-=osc[v].release;
486 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
488 /* the volume offset is because the SID does not
489 completely silence the voices when it should. most
490 emulators do so though and thats the main reason
491 why the sound of emulators is too, err... emulated :) */
492 break;
496 #ifdef USE_FILTER
498 /* now route the voice output to either the non-filtered or the
499 filtered channel and dont forget to blank out osc3 if desired */
501 if (v<2 || filter.v3ena)
503 if (osc[v].filter)
504 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
505 else
506 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
508 #endif
509 #ifndef USE_FILTER
510 /* Don't use filters, just mix all voices together */
511 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
512 #endif
516 #ifdef USE_FILTER
517 /* step 3
518 * so, now theres finally time to apply the multi-mode resonant filter
519 * to the signal. The easiest thing ist just modelling a real electronic
520 * filter circuit instead of fiddling around with complex IIRs or even
521 * FIRs ...
522 * it sounds as good as them or maybe better and needs only 3 MULs and
523 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
524 * Mage messed the whole thing completely up - as the rest of the
525 * emulator.
526 * This filter sounds a lot like the 8580, as the low-quality, dirty
527 * sound of the 6581 is uuh too hard to achieve :) */
529 filter.h = quickfloat_ConvertFromInt(outf) - (filter.b>>8)*filter.rez - filter.l;
530 filter.b += quickfloat_Multiply(filter.freq, filter.h);
531 filter.l += quickfloat_Multiply(filter.freq, filter.b);
533 outf = 0;
535 if (filter.l_ena) outf+=quickfloat_ConvertToInt(filter.l);
536 if (filter.b_ena) outf+=quickfloat_ConvertToInt(filter.b);
537 if (filter.h_ena) outf+=quickfloat_ConvertToInt(filter.h);
539 int final_sample = (filter.vol*(outo+outf));
540 *(buffer+bp)= GenerateDigi(final_sample)<<13;
541 #endif
542 #ifndef USE_FILTER
543 *(buffer+bp) = GenerateDigi(outf)<<3;
544 #endif
551 * C64 Mem Routines
553 static inline unsigned char getmem(unsigned short addr)
555 return memory[addr];
558 static inline void setmem(unsigned short addr, unsigned char value)
560 if ((addr&0xfc00)==0xd400)
562 sidPoke(addr&0x1f,value);
563 /* New SID-Register */
564 if (addr > 0xd418)
566 switch (addr)
568 case 0xd41f: /* Start-Hi */
569 internal_start = (internal_start&0x00ff) | (value<<8); break;
570 case 0xd41e: /* Start-Lo */
571 internal_start = (internal_start&0xff00) | (value); break;
572 case 0xd47f: /* Repeat-Hi */
573 internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
574 case 0xd47e: /* Repeat-Lo */
575 internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
576 case 0xd43e: /* End-Hi */
577 internal_end = (internal_end&0x00ff) | (value<<8); break;
578 case 0xd43d: /* End-Lo */
579 internal_end = (internal_end&0xff00) | (value); break;
580 case 0xd43f: /* Loop-Size */
581 internal_repeat_times = value; break;
582 case 0xd45e: /* Period-Hi */
583 internal_period = (internal_period&0x00ff) | (value<<8); break;
584 case 0xd45d: /* Period-Lo */
585 internal_period = (internal_period&0xff00) | (value); break;
586 case 0xd47d: /* Sample Order */
587 internal_order = value; break;
588 case 0xd45f: /* Sample Add */
589 internal_add = value; break;
590 case 0xd41d: /* Start sampling */
591 sample_repeats = internal_repeat_times;
592 sample_position = internal_start;
593 sample_start = internal_start;
594 sample_end = internal_end;
595 sample_repeat_start = internal_repeat_start;
596 sample_period = internal_period;
597 sample_order = internal_order;
598 switch (value)
600 case 0xfd: sample_active = 0; break;
601 case 0xfe:
602 case 0xff: sample_active = 1; break;
603 default: return;
605 break;
609 else memory[addr]=value;
613 * Poke a value into the sid register
615 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
616 void sidPoke(int reg, unsigned char val)
618 int voice=0;
620 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
621 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
623 switch (reg) {
624 case 0: { /* Set frequency: Low byte */
625 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
626 break;
628 case 1: { /* Set frequency: High byte */
629 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
630 break;
632 case 2: { /* Set pulse width: Low byte */
633 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
634 break;
636 case 3: { /* Set pulse width: High byte */
637 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
638 break;
640 case 4: { sid.v[voice].wave = val;
641 /* Directly look at GATE-Bit!
642 * a change may happen twice or more often during one cpujsr
643 * Put the Envelope Generator into attack or release phase if desired
645 if ((val & 0x01) == 0) osc[voice].envphase=3;
646 else if (osc[voice].envphase==3) osc[voice].envphase=0;
647 break;
650 case 5: { sid.v[voice].ad = val; break;}
651 case 6: { sid.v[voice].sr = val; break;}
653 case 21: { sid.ffreqlo = val; break; }
654 case 22: { sid.ffreqhi = val; break; }
655 case 23: { sid.res_ftv = val; break; }
656 case 24: { sid.ftp_vol = val; break;}
658 return;
661 static inline unsigned char getaddr(int mode)
663 unsigned short ad,ad2;
664 switch(mode)
666 case imp:
667 return 0;
668 case imm:
669 return getmem(pc++);
670 case _abs:
671 ad=getmem(pc++);
672 ad|=256*getmem(pc++);
673 return getmem(ad);
674 case absx:
675 ad=getmem(pc++);
676 ad|=256*getmem(pc++);
677 ad2=ad+x;
678 return getmem(ad2);
679 case absy:
680 ad=getmem(pc++);
681 ad|=256*getmem(pc++);
682 ad2=ad+y;
683 return getmem(ad2);
684 case zp:
685 ad=getmem(pc++);
686 return getmem(ad);
687 case zpx:
688 ad=getmem(pc++);
689 ad+=x;
690 return getmem(ad&0xff);
691 case zpy:
692 ad=getmem(pc++);
693 ad+=y;
694 return getmem(ad&0xff);
695 case indx:
696 ad=getmem(pc++);
697 ad+=x;
698 ad2=getmem(ad&0xff);
699 ad++;
700 ad2|=getmem(ad&0xff)<<8;
701 return getmem(ad2);
702 case indy:
703 ad=getmem(pc++);
704 ad2=getmem(ad);
705 ad2|=getmem((ad+1)&0xff)<<8;
706 ad=ad2+y;
707 return getmem(ad);
708 case acc:
709 return a;
711 return 0;
714 static inline void setaddr(int mode, unsigned char val)
716 unsigned short ad,ad2;
717 switch(mode)
719 case _abs:
720 ad=getmem(pc-2);
721 ad|=256*getmem(pc-1);
722 setmem(ad,val);
723 return;
724 case absx:
725 ad=getmem(pc-2);
726 ad|=256*getmem(pc-1);
727 ad2=ad+x;
728 setmem(ad2,val);
729 return;
730 case zp:
731 ad=getmem(pc-1);
732 setmem(ad,val);
733 return;
734 case zpx:
735 ad=getmem(pc-1);
736 ad+=x;
737 setmem(ad&0xff,val);
738 return;
739 case acc:
740 a=val;
741 return;
746 static inline void putaddr(int mode, unsigned char val)
748 unsigned short ad,ad2;
749 switch(mode)
751 case _abs:
752 ad=getmem(pc++);
753 ad|=getmem(pc++)<<8;
754 setmem(ad,val);
755 return;
756 case absx:
757 ad=getmem(pc++);
758 ad|=getmem(pc++)<<8;
759 ad2=ad+x;
760 setmem(ad2,val);
761 return;
762 case absy:
763 ad=getmem(pc++);
764 ad|=getmem(pc++)<<8;
765 ad2=ad+y;
766 setmem(ad2,val);
767 return;
768 case zp:
769 ad=getmem(pc++);
770 setmem(ad,val);
771 return;
772 case zpx:
773 ad=getmem(pc++);
774 ad+=x;
775 setmem(ad&0xff,val);
776 return;
777 case zpy:
778 ad=getmem(pc++);
779 ad+=y;
780 setmem(ad&0xff,val);
781 return;
782 case indx:
783 ad=getmem(pc++);
784 ad+=x;
785 ad2=getmem(ad&0xff);
786 ad++;
787 ad2|=getmem(ad&0xff)<<8;
788 setmem(ad2,val);
789 return;
790 case indy:
791 ad=getmem(pc++);
792 ad2=getmem(ad);
793 ad2|=getmem((ad+1)&0xff)<<8;
794 ad=ad2+y;
795 setmem(ad,val);
796 return;
797 case acc:
798 a=val;
799 return;
804 static inline void setflags(int flag, int cond)
806 if (cond) p|=flag;
807 else p&=~flag;
811 static inline void push(unsigned char val)
813 setmem(0x100+s,val);
814 if (s) s--;
817 static inline unsigned char pop(void)
819 if (s<0xff) s++;
820 return getmem(0x100+s);
823 static inline void branch(int flag)
825 signed char dist;
826 dist=(signed char)getaddr(imm);
827 wval=pc+dist;
828 if (flag) pc=wval;
831 void cpuReset(void) ICODE_ATTR;
832 void cpuReset(void)
834 a=x=y=0;
835 p=0;
836 s=255;
837 pc=getaddr(0xfffc);
840 void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
841 void cpuResetTo(unsigned short npc, unsigned char na)
843 a=na;
844 x=0;
845 y=0;
846 p=0;
847 s=255;
848 pc=npc;
851 static inline void cpuParse(void)
853 unsigned char opc=getmem(pc++);
854 int cmd=opcodes[opc];
855 int addr=modes[opc];
856 int c;
857 switch (cmd)
859 case adc:
860 wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
861 setflags(FLAG_C, wval&0x100);
862 a=(unsigned char)wval;
863 setflags(FLAG_Z, !a);
864 setflags(FLAG_N, a&0x80);
865 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
866 break;
867 case _and:
868 bval=getaddr(addr);
869 a&=bval;
870 setflags(FLAG_Z, !a);
871 setflags(FLAG_N, a&0x80);
872 break;
873 case asl:
874 wval=getaddr(addr);
875 wval<<=1;
876 setaddr(addr,(unsigned char)wval);
877 setflags(FLAG_Z,!wval);
878 setflags(FLAG_N,wval&0x80);
879 setflags(FLAG_C,wval&0x100);
880 break;
881 case bcc:
882 branch(!(p&FLAG_C));
883 break;
884 case bcs:
885 branch(p&FLAG_C);
886 break;
887 case bne:
888 branch(!(p&FLAG_Z));
889 break;
890 case beq:
891 branch(p&FLAG_Z);
892 break;
893 case bpl:
894 branch(!(p&FLAG_N));
895 break;
896 case bmi:
897 branch(p&FLAG_N);
898 break;
899 case bvc:
900 branch(!(p&FLAG_V));
901 break;
902 case bvs:
903 branch(p&FLAG_V);
904 break;
905 case bit:
906 bval=getaddr(addr);
907 setflags(FLAG_Z,!(a&bval));
908 setflags(FLAG_N,bval&0x80);
909 setflags(FLAG_V,bval&0x40);
910 break;
911 case brk:
912 pc=0; /* Just quit the emulation */
913 break;
914 case clc:
915 setflags(FLAG_C,0);
916 break;
917 case cld:
918 setflags(FLAG_D,0);
919 break;
920 case cli:
921 setflags(FLAG_I,0);
922 break;
923 case clv:
924 setflags(FLAG_V,0);
925 break;
926 case cmp:
927 bval=getaddr(addr);
928 wval=(unsigned short)a-bval;
929 setflags(FLAG_Z,!wval);
930 setflags(FLAG_N,wval&0x80);
931 setflags(FLAG_C,a>=bval);
932 break;
933 case cpx:
934 bval=getaddr(addr);
935 wval=(unsigned short)x-bval;
936 setflags(FLAG_Z,!wval);
937 setflags(FLAG_N,wval&0x80);
938 setflags(FLAG_C,x>=bval);
939 break;
940 case cpy:
941 bval=getaddr(addr);
942 wval=(unsigned short)y-bval;
943 setflags(FLAG_Z,!wval);
944 setflags(FLAG_N,wval&0x80);
945 setflags(FLAG_C,y>=bval);
946 break;
947 case dec:
948 bval=getaddr(addr);
949 bval--;
950 setaddr(addr,bval);
951 setflags(FLAG_Z,!bval);
952 setflags(FLAG_N,bval&0x80);
953 break;
954 case dex:
955 x--;
956 setflags(FLAG_Z,!x);
957 setflags(FLAG_N,x&0x80);
958 break;
959 case dey:
960 y--;
961 setflags(FLAG_Z,!y);
962 setflags(FLAG_N,y&0x80);
963 break;
964 case eor:
965 bval=getaddr(addr);
966 a^=bval;
967 setflags(FLAG_Z,!a);
968 setflags(FLAG_N,a&0x80);
969 break;
970 case inc:
971 bval=getaddr(addr);
972 bval++;
973 setaddr(addr,bval);
974 setflags(FLAG_Z,!bval);
975 setflags(FLAG_N,bval&0x80);
976 break;
977 case inx:
978 x++;
979 setflags(FLAG_Z,!x);
980 setflags(FLAG_N,x&0x80);
981 break;
982 case iny:
983 y++;
984 setflags(FLAG_Z,!y);
985 setflags(FLAG_N,y&0x80);
986 break;
987 case jmp:
988 wval=getmem(pc++);
989 wval|=256*getmem(pc++);
990 switch (addr)
992 case _abs:
993 pc=wval;
994 break;
995 case ind:
996 pc=getmem(wval);
997 pc|=256*getmem(wval+1);
998 break;
1000 break;
1001 case jsr:
1002 push((pc+1)>>8);
1003 push((pc+1));
1004 wval=getmem(pc++);
1005 wval|=256*getmem(pc++);
1006 pc=wval;
1007 break;
1008 case lda:
1009 a=getaddr(addr);
1010 setflags(FLAG_Z,!a);
1011 setflags(FLAG_N,a&0x80);
1012 break;
1013 case ldx:
1014 x=getaddr(addr);
1015 setflags(FLAG_Z,!x);
1016 setflags(FLAG_N,x&0x80);
1017 break;
1018 case ldy:
1019 y=getaddr(addr);
1020 setflags(FLAG_Z,!y);
1021 setflags(FLAG_N,y&0x80);
1022 break;
1023 case lsr:
1024 bval=getaddr(addr); wval=(unsigned char)bval;
1025 wval>>=1;
1026 setaddr(addr,(unsigned char)wval);
1027 setflags(FLAG_Z,!wval);
1028 setflags(FLAG_N,wval&0x80);
1029 setflags(FLAG_C,bval&1);
1030 break;
1031 case _nop:
1032 break;
1033 case ora:
1034 bval=getaddr(addr);
1035 a|=bval;
1036 setflags(FLAG_Z,!a);
1037 setflags(FLAG_N,a&0x80);
1038 break;
1039 case pha:
1040 push(a);
1041 break;
1042 case php:
1043 push(p);
1044 break;
1045 case pla:
1046 a=pop();
1047 setflags(FLAG_Z,!a);
1048 setflags(FLAG_N,a&0x80);
1049 break;
1050 case plp:
1051 p=pop();
1052 break;
1053 case rol:
1054 bval=getaddr(addr);
1055 c=!!(p&FLAG_C);
1056 setflags(FLAG_C,bval&0x80);
1057 bval<<=1;
1058 bval|=c;
1059 setaddr(addr,bval);
1060 setflags(FLAG_N,bval&0x80);
1061 setflags(FLAG_Z,!bval);
1062 break;
1063 case ror:
1064 bval=getaddr(addr);
1065 c=!!(p&FLAG_C);
1066 setflags(FLAG_C,bval&1);
1067 bval>>=1;
1068 bval|=128*c;
1069 setaddr(addr,bval);
1070 setflags(FLAG_N,bval&0x80);
1071 setflags(FLAG_Z,!bval);
1072 break;
1073 case rti:
1074 /* Treat RTI like RTS */
1075 case rts:
1076 wval=pop();
1077 wval|=pop()<<8;
1078 pc=wval+1;
1079 break;
1080 case sbc:
1081 bval=getaddr(addr)^0xff;
1082 wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
1083 setflags(FLAG_C, wval&0x100);
1084 a=(unsigned char)wval;
1085 setflags(FLAG_Z, !a);
1086 setflags(FLAG_N, a>127);
1087 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
1088 break;
1089 case sec:
1090 setflags(FLAG_C,1);
1091 break;
1092 case sed:
1093 setflags(FLAG_D,1);
1094 break;
1095 case sei:
1096 setflags(FLAG_I,1);
1097 break;
1098 case sta:
1099 putaddr(addr,a);
1100 break;
1101 case stx:
1102 putaddr(addr,x);
1103 break;
1104 case sty:
1105 putaddr(addr,y);
1106 break;
1107 case tax:
1108 x=a;
1109 setflags(FLAG_Z, !x);
1110 setflags(FLAG_N, x&0x80);
1111 break;
1112 case tay:
1113 y=a;
1114 setflags(FLAG_Z, !y);
1115 setflags(FLAG_N, y&0x80);
1116 break;
1117 case tsx:
1118 x=s;
1119 setflags(FLAG_Z, !x);
1120 setflags(FLAG_N, x&0x80);
1121 break;
1122 case txa:
1123 a=x;
1124 setflags(FLAG_Z, !a);
1125 setflags(FLAG_N, a&0x80);
1126 break;
1127 case txs:
1128 s=x;
1129 break;
1130 case tya:
1131 a=y;
1132 setflags(FLAG_Z, !a);
1133 setflags(FLAG_N, a&0x80);
1134 break;
1138 void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1139 void cpuJSR(unsigned short npc, unsigned char na)
1141 a=na;
1142 x=0;
1143 y=0;
1144 p=0;
1145 s=255;
1146 pc=npc;
1147 push(0);
1148 push(0);
1150 while (pc > 1)
1151 cpuParse();
1155 void c64Init(int nSampleRate) ICODE_ATTR;
1156 void c64Init(int nSampleRate)
1158 synth_init(nSampleRate);
1159 memset(memory, 0, sizeof(memory));
1161 cpuReset();
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) ICODE_ATTR;
1168 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1169 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
1171 unsigned char *pData;
1172 unsigned char data_file_offset;
1174 pData = (unsigned char*)pSidData;
1175 data_file_offset = pData[7];
1177 *load_addr = pData[8]<<8;
1178 *load_addr|= pData[9];
1180 *init_addr = pData[10]<<8;
1181 *init_addr|= pData[11];
1183 *play_addr = pData[12]<<8;
1184 *play_addr|= pData[13];
1186 *subsongs = pData[0xf]-1;
1187 *startsong = pData[0x11]-1;
1189 *load_addr = pData[data_file_offset];
1190 *load_addr|= pData[data_file_offset+1]<<8;
1192 *speed = pData[0x15];
1194 memset(memory, 0, sizeof(memory));
1195 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1197 if (*play_addr == 0)
1199 cpuJSR(*init_addr, 0);
1200 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1203 return *load_addr;
1207 enum codec_status codec_main(void)
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 next_track:
1219 if (codec_init()) {
1220 return CODEC_ERROR;
1223 while (!*ci->taginfo_ready && !ci->stop_codec)
1224 ci->sleep(1);
1226 codec_set_replaygain(ci->id3);
1228 /* Load SID file the read_filebuf callback will return the full requested
1229 * size if at all possible, so there is no need to loop */
1230 filesize = ci->read_filebuf(sidfile, sizeof(sidfile));
1232 if (filesize == 0)
1233 return CODEC_ERROR;
1235 c64Init(44100);
1236 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1237 &subSongsMax, &subSong, &song_speed, filesize);
1238 sidPoke(24, 15); /* Turn on full volume */
1239 cpuJSR(init_addr, subSong); /* Start the song initialize */
1242 /* Make use of 44.1khz */
1243 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1244 /* Sample depth is 28 bit host endian */
1245 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1246 /* Mono output */
1247 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1250 /* Set the elapsed time to the current subsong (in seconds) */
1251 ci->set_elapsed(subSong*1000);
1253 /* The main decoder loop */
1254 while (1) {
1255 ci->yield();
1256 if (ci->stop_codec || ci->new_track)
1257 break;
1259 if (ci->seek_time) {
1260 /* New time is ready in ci->seek_time */
1262 /* Start playing from scratch */
1263 c64Init(44100);
1264 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, &subSongsMax, &subSong, &song_speed, filesize);
1265 sidPoke(24, 15); /* Turn on full volume */
1266 subSong = ci->seek_time / 1000; /* Now use the current seek time in seconds as subsong */
1267 cpuJSR(init_addr, subSong); /* Start the song initialize */
1268 nSamplesToRender = 0; /* Start the rendering from scratch */
1270 ci->seek_complete();
1272 /* Set the elapsed time to the current subsong (in seconds) */
1273 ci->set_elapsed(subSong*1000);
1276 nSamplesRendered = 0;
1277 while (nSamplesRendered < CHUNK_SIZE)
1279 if (nSamplesToRender == 0)
1281 cpuJSR(play_addr, 0);
1283 /* Find out if cia timing is used and how many samples
1284 have to be calculated for each cpujsr */
1285 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
1286 if ((nRefreshCIA==0) || (song_speed == 0))
1287 nRefreshCIA = 20000;
1288 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1290 nSamplesToRender = nSamplesPerCall;
1292 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1294 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1295 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1296 nSamplesRendered = CHUNK_SIZE;
1298 else
1300 synth_render(samples+nSamplesRendered, nSamplesToRender);
1301 nSamplesRendered += nSamplesToRender;
1302 nSamplesToRender = 0;
1306 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1309 if (ci->request_next_track())
1310 goto next_track;
1312 return CODEC_OK;