The manual should reflect that some synthesizer codecs are switched off for low memor...
[kugel-rb.git] / apps / codecs / sid.c
blobfed1e8acaaf52f688cc2b3f846a0cc1dd13da0af
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)
69 #define SID_BUFFER_SIZE 0x10000
70 #define SAMPLE_RATE 44100
72 /* This codec supports SID Files:
76 static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
78 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
80 #define FLAG_N 128
81 #define FLAG_V 64
82 #define FLAG_B 16
83 #define FLAG_D 8
84 #define FLAG_I 4
85 #define FLAG_Z 2
86 #define FLAG_C 1
88 #define imp 0
89 #define imm 1
90 #define _abs 2
91 #define absx 3
92 #define absy 4
93 #define zp 6
94 #define zpx 7
95 #define zpy 8
96 #define ind 9
97 #define indx 10
98 #define indy 11
99 #define acc 12
100 #define rel 13
102 enum {
103 adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, _brk, bvc, bvs, clc,
104 cld, cli, clv, cmp, cpx, cpy, dec, dex, dey, eor, inc, inx, iny, jmp,
105 jsr, lda, ldx, ldy, lsr, _nop, ora, pha, php, pla, plp, rol, ror, rti,
106 rts, sbc, sec, sed, sei, sta, stx, sty, tax, tay, tsx, txa, txs, tya,
110 /* SID register definition */
111 struct s6581 {
112 struct sidvoice {
113 unsigned short freq;
114 unsigned short pulse;
115 unsigned char wave;
116 unsigned char ad;
117 unsigned char sr;
118 } v[3];
119 unsigned char ffreqlo;
120 unsigned char ffreqhi;
121 unsigned char res_ftv;
122 unsigned char ftp_vol;
125 /* internal oscillator def */
126 struct sidosc {
127 unsigned long freq;
128 unsigned long pulse;
129 unsigned char wave;
130 unsigned char filter;
131 unsigned long attack;
132 unsigned long decay;
133 unsigned long sustain;
134 unsigned long release;
135 unsigned long counter;
136 signed long envval;
137 unsigned char envphase;
138 unsigned long noisepos;
139 unsigned long noiseval;
140 unsigned char noiseout;
143 /* internal filter def */
144 struct sidflt {
145 int freq;
146 unsigned char l_ena;
147 unsigned char b_ena;
148 unsigned char h_ena;
149 unsigned char v3ena;
150 int vol;
151 int rez;
152 int h;
153 int b;
154 int l;
157 /* ------------------------ pseudo-constants (depending on mixing freq) */
158 int mixing_frequency IDATA_ATTR;
159 unsigned long freqmul IDATA_ATTR;
160 int filtmul IDATA_ATTR;
161 #ifndef ROCKBOX
162 unsigned long attacks [16] IDATA_ATTR;
163 unsigned long releases[16] IDATA_ATTR;
164 #endif
166 /* ------------------------------------------------------------ globals */
167 struct s6581 sid IDATA_ATTR;
168 struct sidosc osc[3] IDATA_ATTR;
169 struct sidflt filter IDATA_ATTR;
171 /* ------------------------------------------------------ C64 Emu Stuff */
172 unsigned char bval IDATA_ATTR;
173 unsigned short wval IDATA_ATTR;
174 /* -------------------------------------------------- Register & memory */
175 unsigned char a,x,y,s,p IDATA_ATTR;
176 unsigned short pc IDATA_ATTR;
178 unsigned char memory[65536];
180 /* ----------------------------------------- Variables for sample stuff */
181 static int sample_active IDATA_ATTR;
182 static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
183 static int fracPos IDATA_ATTR; /* Fractal position of sample */
184 static int sample_period IDATA_ATTR;
185 static int sample_repeats IDATA_ATTR;
186 static int sample_order IDATA_ATTR;
187 static int sample_nibble IDATA_ATTR;
189 static int internal_period, internal_order, internal_start, internal_end,
190 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
192 /* ---------------------------------------------------------- constants */
193 #ifndef ROCKBOX
194 static const float attackTimes[16] ICONST_ATTR =
196 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
197 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
198 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
199 0.977715461, 2.93364701, 4.88907793, 7.82272493
201 static const float decayReleaseTimes[16] ICONST_ATTR =
203 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
204 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
205 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
207 #else
208 #define DIV(X) ((int)(0x1000000 / (X * SAMPLE_RATE)))
209 static const unsigned long attacks[16] ICONST_ATTR =
211 DIV(0.0022528606), DIV(0.0080099577), DIV(0.0157696042), DIV(0.0237795619),
212 DIV(0.0372963655), DIV(0.0550684591), DIV(0.0668330845), DIV(0.0783473987),
213 DIV(0.0981219818), DIV(0.2445540210), DIV(0.4891080420), DIV(0.7824727420),
214 DIV(0.9777154610), DIV(2.9336470100), DIV(4.8890779300), DIV(7.8227249300)
216 static const unsigned long releases[16] ICONST_ATTR =
218 DIV(0.00891777693), DIV(0.0245940510), DIV(0.0484185907), DIV(0.0730116639),
219 DIV(0.11451247500), DIV(0.1690783560), DIV(0.2051994320), DIV(0.2405519750),
220 DIV(0.30126612500), DIV(0.7508582450), DIV(1.5017155100), DIV(2.4024368200),
221 DIV(3.00189298000), DIV(9.0072140500), DIV(15.010998000), DIV(24.018211100)
223 #endif
224 static const int opcodes[256] ICONST_ATTR = {
225 _brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
226 bpl,ora,xxx,xxx,xxx,ora,asl,xxx,clc,ora,xxx,xxx,xxx,ora,asl,xxx,
227 jsr,_and,xxx,xxx,bit,_and,rol,xxx,plp,_and,rol,xxx,bit,_and,rol,xxx,
228 bmi,_and,xxx,xxx,xxx,_and,rol,xxx,sec,_and,xxx,xxx,xxx,_and,rol,xxx,
229 rti,eor,xxx,xxx,xxx,eor,lsr,xxx,pha,eor,lsr,xxx,jmp,eor,lsr,xxx,
230 bvc,eor,xxx,xxx,xxx,eor,lsr,xxx,cli,eor,xxx,xxx,xxx,eor,lsr,xxx,
231 rts,adc,xxx,xxx,xxx,adc,ror,xxx,pla,adc,ror,xxx,jmp,adc,ror,xxx,
232 bvs,adc,xxx,xxx,xxx,adc,ror,xxx,sei,adc,xxx,xxx,xxx,adc,ror,xxx,
233 xxx,sta,xxx,xxx,sty,sta,stx,xxx,dey,xxx,txa,xxx,sty,sta,stx,xxx,
234 bcc,sta,xxx,xxx,sty,sta,stx,xxx,tya,sta,txs,xxx,xxx,sta,xxx,xxx,
235 ldy,lda,ldx,xxx,ldy,lda,ldx,xxx,tay,lda,tax,xxx,ldy,lda,ldx,xxx,
236 bcs,lda,xxx,xxx,ldy,lda,ldx,xxx,clv,lda,tsx,xxx,ldy,lda,ldx,xxx,
237 cpy,cmp,xxx,xxx,cpy,cmp,dec,xxx,iny,cmp,dex,xxx,cpy,cmp,dec,xxx,
238 bne,cmp,xxx,xxx,xxx,cmp,dec,xxx,cld,cmp,xxx,xxx,xxx,cmp,dec,xxx,
239 cpx,sbc,xxx,xxx,cpx,sbc,inc,xxx,inx,sbc,_nop,xxx,cpx,sbc,inc,xxx,
240 beq,sbc,xxx,xxx,xxx,sbc,inc,xxx,sed,sbc,xxx,xxx,xxx,sbc,inc,xxx
244 static const int modes[256] ICONST_ATTR = {
245 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
246 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
247 _abs,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
248 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
249 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
250 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
251 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,ind,_abs,_abs,xxx,
252 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
253 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
254 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
255 imm,indx,imm,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
256 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,absx,absx,absy,xxx,
257 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
258 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
259 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
260 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx
263 /* Routines for quick & dirty float calculation */
265 static inline int quickfloat_ConvertFromInt(int i)
267 return (i<<16);
269 #ifndef ROCKBOX
270 static inline int quickfloat_ConvertFromFloat(float f)
272 return (int)(f*(1<<16));
274 #else
275 #define quickfloat_ConvertFromFloat(X) (int)(X*(1<<16))
276 #endif
277 static inline int quickfloat_Multiply(int a, int b)
279 return (a>>8)*(b>>8);
281 static inline int quickfloat_ConvertToInt(int i)
283 return (i>>16);
286 /* Get the bit from an unsigned long at a specified position */
287 static inline unsigned char get_bit(unsigned long val, unsigned char b)
289 return (unsigned char) ((val >> b) & 1);
293 static inline int GenerateDigi(int sIn)
295 static int sample = 0;
297 if (!sample_active) return(sIn);
299 if ((sample_position < sample_end) && (sample_position >= sample_start))
301 sIn += sample;
303 fracPos += 985248/sample_period;
305 if (fracPos > mixing_frequency)
307 fracPos%=mixing_frequency;
309 // N�hstes Samples holen
310 if (sample_order == 0) {
311 sample_nibble++; // Nähstes Sample-Nibble
312 if (sample_nibble==2) {
313 sample_nibble = 0;
314 sample_position++;
317 else {
318 sample_nibble--;
319 if (sample_nibble < 0) {
320 sample_nibble=1;
321 sample_position++;
324 if (sample_repeats)
326 if (sample_position > sample_end)
328 sample_repeats--;
329 sample_position = sample_repeat_start;
331 else sample_active = 0;
334 sample = memory[sample_position&0xffff];
335 if (sample_nibble==1) // Hi-Nibble holen?
336 sample = (sample & 0xf0)>>4;
337 else sample = sample & 0x0f;
339 sample -= 7;
340 sample <<= 10;
344 return (sIn);
347 /* ------------------------------------------------------------- synthesis
348 initialize SID and frequency dependant values */
349 void synth_init(unsigned long mixfrq) ICODE_ATTR;
350 void synth_init(unsigned long mixfrq)
352 #ifndef ROCKBOX
353 int i;
354 #endif
355 mixing_frequency = mixfrq;
356 fracPos = 0;
357 freqmul = 15872000 / mixfrq;
358 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
359 #ifndef ROCKBOX
360 for (i=0;i<16;i++) {
361 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
362 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
364 #endif
365 memset(&sid,0,sizeof(sid));
366 memset(osc,0,sizeof(osc));
367 memset(&filter,0,sizeof(filter));
368 osc[0].noiseval = 0xffffff;
369 osc[1].noiseval = 0xffffff;
370 osc[2].noiseval = 0xffffff;
373 /* render a buffer of n samples with the actual register contents */
374 void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
375 void synth_render (int32_t *buffer, unsigned long len)
377 unsigned long bp;
378 /* step 1: convert the not easily processable sid registers into some
379 more convenient and fast values (makes the thing much faster
380 if you process more than 1 sample value at once) */
381 unsigned char v;
382 for (v=0;v<3;v++) {
383 osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
384 osc[v].filter = get_bit(sid.res_ftv,v);
385 osc[v].attack = attacks[sid.v[v].ad >> 4];
386 osc[v].decay = releases[sid.v[v].ad & 0xf];
387 osc[v].sustain = sid.v[v].sr & 0xf0;
388 osc[v].release = releases[sid.v[v].sr & 0xf];
389 osc[v].wave = sid.v[v].wave;
390 osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
393 #ifdef USE_FILTER
394 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
396 if (filter.freq>quickfloat_ConvertFromInt(1))
397 filter.freq=quickfloat_ConvertFromInt(1);
398 /* the above line isnt correct at all - the problem is that the filter
399 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
400 for 32KHz and lower - well, but sound quality is bad enough then to
401 neglect the fact that the filter doesnt come that high ;) */
402 filter.l_ena = get_bit(sid.ftp_vol,4);
403 filter.b_ena = get_bit(sid.ftp_vol,5);
404 filter.h_ena = get_bit(sid.ftp_vol,6);
405 filter.v3ena = !get_bit(sid.ftp_vol,7);
406 filter.vol = (sid.ftp_vol & 0xf);
407 filter.rez = quickfloat_ConvertFromFloat(1.2f) -
408 quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
410 /* We precalculate part of the quick float operation, saves time in loop later */
411 filter.rez>>=8;
412 #endif
415 /* now render the buffer */
416 for (bp=0;bp<len;bp++) {
417 #ifdef USE_FILTER
418 int outo=0;
419 #endif
420 int outf=0;
421 /* step 2 : generate the two output signals (for filtered and non-
422 filtered) from the osc/eg sections */
423 for (v=0;v<3;v++) {
424 /* update wave counter */
425 osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
426 /* reset counter / noise generator if reset get_bit set */
427 if (osc[v].wave & 0x08) {
428 osc[v].counter = 0;
429 osc[v].noisepos = 0;
430 osc[v].noiseval = 0xffffff;
432 unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
433 /* sync oscillator to refosc if sync bit set */
434 if (osc[v].wave & 0x02)
435 if (osc[refosc].counter < osc[refosc].freq)
436 osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
437 /* generate waveforms with really simple algorithms */
438 unsigned char triout = (unsigned char) (osc[v].counter>>19);
439 if (osc[v].counter>>27)
440 triout^=0xff;
441 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
442 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
444 /* generate noise waveform exactly as the SID does. */
445 if (osc[v].noisepos!=(osc[v].counter>>23))
447 osc[v].noisepos = osc[v].counter >> 23;
448 osc[v].noiseval = (osc[v].noiseval << 1) |
449 (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
450 osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
451 (get_bit(osc[v].noiseval,20) << 6) |
452 (get_bit(osc[v].noiseval,16) << 5) |
453 (get_bit(osc[v].noiseval,13) << 4) |
454 (get_bit(osc[v].noiseval,11) << 3) |
455 (get_bit(osc[v].noiseval, 7) << 2) |
456 (get_bit(osc[v].noiseval, 4) << 1) |
457 (get_bit(osc[v].noiseval, 2) << 0);
459 unsigned char nseout = osc[v].noiseout;
461 /* modulate triangle wave if ringmod bit set */
462 if (osc[v].wave & 0x04)
463 if (osc[refosc].counter < 0x8000000)
464 triout ^= 0xff;
466 /* now mix the oscillators with an AND operation as stated in
467 the SID's reference manual - even if this is completely wrong.
468 well, at least, the $30 and $70 waveform sounds correct and there's
469 no real solution to do $50 and $60, so who cares. */
471 unsigned char outv=0xFF;
472 if (osc[v].wave & 0x10) outv &= triout;
473 if (osc[v].wave & 0x20) outv &= sawout;
474 if (osc[v].wave & 0x40) outv &= plsout;
475 if (osc[v].wave & 0x80) outv &= nseout;
477 /* so now process the volume according to the phase and adsr values */
478 switch (osc[v].envphase) {
479 case 0 : { /* Phase 0 : Attack */
480 osc[v].envval+=osc[v].attack;
481 if (osc[v].envval >= 0xFFFFFF)
483 osc[v].envval = 0xFFFFFF;
484 osc[v].envphase = 1;
486 break;
488 case 1 : { /* Phase 1 : Decay */
489 osc[v].envval-=osc[v].decay;
490 if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
492 osc[v].envval = osc[v].sustain<<16;
493 osc[v].envphase = 2;
495 break;
497 case 2 : { /* Phase 2 : Sustain */
498 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
500 osc[v].envphase = 1;
502 /* :) yes, thats exactly how the SID works. and maybe
503 a music routine out there supports this, so better
504 let it in, thanks :) */
505 break;
507 case 3 : { /* Phase 3 : Release */
508 osc[v].envval-=osc[v].release;
509 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
511 /* the volume offset is because the SID does not
512 completely silence the voices when it should. most
513 emulators do so though and thats the main reason
514 why the sound of emulators is too, err... emulated :) */
515 break;
519 #ifdef USE_FILTER
521 /* now route the voice output to either the non-filtered or the
522 filtered channel and dont forget to blank out osc3 if desired */
524 if (v<2 || filter.v3ena)
526 if (osc[v].filter)
527 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
528 else
529 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
531 #endif
532 #ifndef USE_FILTER
533 /* Don't use filters, just mix all voices together */
534 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
535 #endif
539 #ifdef USE_FILTER
540 /* step 3
541 * so, now theres finally time to apply the multi-mode resonant filter
542 * to the signal. The easiest thing ist just modelling a real electronic
543 * filter circuit instead of fiddling around with complex IIRs or even
544 * FIRs ...
545 * it sounds as good as them or maybe better and needs only 3 MULs and
546 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
547 * Mage messed the whole thing completely up - as the rest of the
548 * emulator.
549 * This filter sounds a lot like the 8580, as the low-quality, dirty
550 * sound of the 6581 is uuh too hard to achieve :) */
552 filter.h = quickfloat_ConvertFromInt(outf) - (filter.b>>8)*filter.rez - filter.l;
553 filter.b += quickfloat_Multiply(filter.freq, filter.h);
554 filter.l += quickfloat_Multiply(filter.freq, filter.b);
556 outf = 0;
558 if (filter.l_ena) outf+=quickfloat_ConvertToInt(filter.l);
559 if (filter.b_ena) outf+=quickfloat_ConvertToInt(filter.b);
560 if (filter.h_ena) outf+=quickfloat_ConvertToInt(filter.h);
562 int final_sample = (filter.vol*(outo+outf));
563 *(buffer+bp)= GenerateDigi(final_sample)<<13;
564 #endif
565 #ifndef USE_FILTER
566 *(buffer+bp) = GenerateDigi(outf)<<3;
567 #endif
574 * C64 Mem Routines
576 static inline unsigned char getmem(unsigned short addr)
578 return memory[addr];
581 static inline void setmem(unsigned short addr, unsigned char value)
583 if ((addr&0xfc00)==0xd400)
585 sidPoke(addr&0x1f,value);
586 /* New SID-Register */
587 if (addr > 0xd418)
589 switch (addr)
591 case 0xd41f: /* Start-Hi */
592 internal_start = (internal_start&0x00ff) | (value<<8); break;
593 case 0xd41e: /* Start-Lo */
594 internal_start = (internal_start&0xff00) | (value); break;
595 case 0xd47f: /* Repeat-Hi */
596 internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
597 case 0xd47e: /* Repeat-Lo */
598 internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
599 case 0xd43e: /* End-Hi */
600 internal_end = (internal_end&0x00ff) | (value<<8); break;
601 case 0xd43d: /* End-Lo */
602 internal_end = (internal_end&0xff00) | (value); break;
603 case 0xd43f: /* Loop-Size */
604 internal_repeat_times = value; break;
605 case 0xd45e: /* Period-Hi */
606 internal_period = (internal_period&0x00ff) | (value<<8); break;
607 case 0xd45d: /* Period-Lo */
608 internal_period = (internal_period&0xff00) | (value); break;
609 case 0xd47d: /* Sample Order */
610 internal_order = value; break;
611 case 0xd45f: /* Sample Add */
612 internal_add = value; break;
613 case 0xd41d: /* Start sampling */
614 sample_repeats = internal_repeat_times;
615 sample_position = internal_start;
616 sample_start = internal_start;
617 sample_end = internal_end;
618 sample_repeat_start = internal_repeat_start;
619 sample_period = internal_period;
620 sample_order = internal_order;
621 switch (value)
623 case 0xfd: sample_active = 0; break;
624 case 0xfe:
625 case 0xff: sample_active = 1; break;
626 default: return;
628 break;
632 else memory[addr]=value;
636 * Poke a value into the sid register
638 void sidPoke(int reg, unsigned char val) ICODE_ATTR;
639 void sidPoke(int reg, unsigned char val)
641 int voice=0;
643 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
644 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
646 switch (reg) {
647 case 0: { /* Set frequency: Low byte */
648 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
649 break;
651 case 1: { /* Set frequency: High byte */
652 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
653 break;
655 case 2: { /* Set pulse width: Low byte */
656 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
657 break;
659 case 3: { /* Set pulse width: High byte */
660 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
661 break;
663 case 4: { sid.v[voice].wave = val;
664 /* Directly look at GATE-Bit!
665 * a change may happen twice or more often during one cpujsr
666 * Put the Envelope Generator into attack or release phase if desired
668 if ((val & 0x01) == 0) osc[voice].envphase=3;
669 else if (osc[voice].envphase==3) osc[voice].envphase=0;
670 break;
673 case 5: { sid.v[voice].ad = val; break;}
674 case 6: { sid.v[voice].sr = val; break;}
676 case 21: { sid.ffreqlo = val; break; }
677 case 22: { sid.ffreqhi = val; break; }
678 case 23: { sid.res_ftv = val; break; }
679 case 24: { sid.ftp_vol = val; break;}
681 return;
684 static inline unsigned char getaddr(int mode)
686 unsigned short ad,ad2;
687 switch(mode)
689 case imp:
690 return 0;
691 case imm:
692 return getmem(pc++);
693 case _abs:
694 ad=getmem(pc++);
695 ad|=256*getmem(pc++);
696 return getmem(ad);
697 case absx:
698 ad=getmem(pc++);
699 ad|=256*getmem(pc++);
700 ad2=ad+x;
701 return getmem(ad2);
702 case absy:
703 ad=getmem(pc++);
704 ad|=256*getmem(pc++);
705 ad2=ad+y;
706 return getmem(ad2);
707 case zp:
708 ad=getmem(pc++);
709 return getmem(ad);
710 case zpx:
711 ad=getmem(pc++);
712 ad+=x;
713 return getmem(ad&0xff);
714 case zpy:
715 ad=getmem(pc++);
716 ad+=y;
717 return getmem(ad&0xff);
718 case indx:
719 ad=getmem(pc++);
720 ad+=x;
721 ad2=getmem(ad&0xff);
722 ad++;
723 ad2|=getmem(ad&0xff)<<8;
724 return getmem(ad2);
725 case indy:
726 ad=getmem(pc++);
727 ad2=getmem(ad);
728 ad2|=getmem((ad+1)&0xff)<<8;
729 ad=ad2+y;
730 return getmem(ad);
731 case acc:
732 return a;
734 return 0;
737 static inline void setaddr(int mode, unsigned char val)
739 unsigned short ad,ad2;
740 switch(mode)
742 case _abs:
743 ad=getmem(pc-2);
744 ad|=256*getmem(pc-1);
745 setmem(ad,val);
746 return;
747 case absx:
748 ad=getmem(pc-2);
749 ad|=256*getmem(pc-1);
750 ad2=ad+x;
751 setmem(ad2,val);
752 return;
753 case zp:
754 ad=getmem(pc-1);
755 setmem(ad,val);
756 return;
757 case zpx:
758 ad=getmem(pc-1);
759 ad+=x;
760 setmem(ad&0xff,val);
761 return;
762 case acc:
763 a=val;
764 return;
769 static inline void putaddr(int mode, unsigned char val)
771 unsigned short ad,ad2;
772 switch(mode)
774 case _abs:
775 ad=getmem(pc++);
776 ad|=getmem(pc++)<<8;
777 setmem(ad,val);
778 return;
779 case absx:
780 ad=getmem(pc++);
781 ad|=getmem(pc++)<<8;
782 ad2=ad+x;
783 setmem(ad2,val);
784 return;
785 case absy:
786 ad=getmem(pc++);
787 ad|=getmem(pc++)<<8;
788 ad2=ad+y;
789 setmem(ad2,val);
790 return;
791 case zp:
792 ad=getmem(pc++);
793 setmem(ad,val);
794 return;
795 case zpx:
796 ad=getmem(pc++);
797 ad+=x;
798 setmem(ad&0xff,val);
799 return;
800 case zpy:
801 ad=getmem(pc++);
802 ad+=y;
803 setmem(ad&0xff,val);
804 return;
805 case indx:
806 ad=getmem(pc++);
807 ad+=x;
808 ad2=getmem(ad&0xff);
809 ad++;
810 ad2|=getmem(ad&0xff)<<8;
811 setmem(ad2,val);
812 return;
813 case indy:
814 ad=getmem(pc++);
815 ad2=getmem(ad);
816 ad2|=getmem((ad+1)&0xff)<<8;
817 ad=ad2+y;
818 setmem(ad,val);
819 return;
820 case acc:
821 a=val;
822 return;
827 static inline void setflags(int flag, int cond)
829 if (cond) p|=flag;
830 else p&=~flag;
834 static inline void push(unsigned char val)
836 setmem(0x100+s,val);
837 if (s) s--;
840 static inline unsigned char pop(void)
842 if (s<0xff) s++;
843 return getmem(0x100+s);
846 static inline void branch(int flag)
848 signed char dist;
849 dist=(signed char)getaddr(imm);
850 wval=pc+dist;
851 if (flag) pc=wval;
854 void cpuReset(void) ICODE_ATTR;
855 void cpuReset(void)
857 a=x=y=0;
858 p=0;
859 s=255;
860 pc=getaddr(0xfffc);
863 void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
864 void cpuResetTo(unsigned short npc, unsigned char na)
866 a=na;
867 x=0;
868 y=0;
869 p=0;
870 s=255;
871 pc=npc;
874 static inline void cpuParse(void)
876 unsigned char opc=getmem(pc++);
877 int cmd=opcodes[opc];
878 int addr=modes[opc];
879 int c;
880 switch (cmd)
882 case adc:
883 wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
884 setflags(FLAG_C, wval&0x100);
885 a=(unsigned char)wval;
886 setflags(FLAG_Z, !a);
887 setflags(FLAG_N, a&0x80);
888 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
889 break;
890 case _and:
891 bval=getaddr(addr);
892 a&=bval;
893 setflags(FLAG_Z, !a);
894 setflags(FLAG_N, a&0x80);
895 break;
896 case asl:
897 wval=getaddr(addr);
898 wval<<=1;
899 setaddr(addr,(unsigned char)wval);
900 setflags(FLAG_Z,!wval);
901 setflags(FLAG_N,wval&0x80);
902 setflags(FLAG_C,wval&0x100);
903 break;
904 case bcc:
905 branch(!(p&FLAG_C));
906 break;
907 case bcs:
908 branch(p&FLAG_C);
909 break;
910 case bne:
911 branch(!(p&FLAG_Z));
912 break;
913 case beq:
914 branch(p&FLAG_Z);
915 break;
916 case bpl:
917 branch(!(p&FLAG_N));
918 break;
919 case bmi:
920 branch(p&FLAG_N);
921 break;
922 case bvc:
923 branch(!(p&FLAG_V));
924 break;
925 case bvs:
926 branch(p&FLAG_V);
927 break;
928 case bit:
929 bval=getaddr(addr);
930 setflags(FLAG_Z,!(a&bval));
931 setflags(FLAG_N,bval&0x80);
932 setflags(FLAG_V,bval&0x40);
933 break;
934 case _brk:
935 pc=0; /* Just quit the emulation */
936 break;
937 case clc:
938 setflags(FLAG_C,0);
939 break;
940 case cld:
941 setflags(FLAG_D,0);
942 break;
943 case cli:
944 setflags(FLAG_I,0);
945 break;
946 case clv:
947 setflags(FLAG_V,0);
948 break;
949 case cmp:
950 bval=getaddr(addr);
951 wval=(unsigned short)a-bval;
952 setflags(FLAG_Z,!wval);
953 setflags(FLAG_N,wval&0x80);
954 setflags(FLAG_C,a>=bval);
955 break;
956 case cpx:
957 bval=getaddr(addr);
958 wval=(unsigned short)x-bval;
959 setflags(FLAG_Z,!wval);
960 setflags(FLAG_N,wval&0x80);
961 setflags(FLAG_C,x>=bval);
962 break;
963 case cpy:
964 bval=getaddr(addr);
965 wval=(unsigned short)y-bval;
966 setflags(FLAG_Z,!wval);
967 setflags(FLAG_N,wval&0x80);
968 setflags(FLAG_C,y>=bval);
969 break;
970 case dec:
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 dex:
978 x--;
979 setflags(FLAG_Z,!x);
980 setflags(FLAG_N,x&0x80);
981 break;
982 case dey:
983 y--;
984 setflags(FLAG_Z,!y);
985 setflags(FLAG_N,y&0x80);
986 break;
987 case eor:
988 bval=getaddr(addr);
989 a^=bval;
990 setflags(FLAG_Z,!a);
991 setflags(FLAG_N,a&0x80);
992 break;
993 case inc:
994 bval=getaddr(addr);
995 bval++;
996 setaddr(addr,bval);
997 setflags(FLAG_Z,!bval);
998 setflags(FLAG_N,bval&0x80);
999 break;
1000 case inx:
1001 x++;
1002 setflags(FLAG_Z,!x);
1003 setflags(FLAG_N,x&0x80);
1004 break;
1005 case iny:
1006 y++;
1007 setflags(FLAG_Z,!y);
1008 setflags(FLAG_N,y&0x80);
1009 break;
1010 case jmp:
1011 wval=getmem(pc++);
1012 wval|=256*getmem(pc++);
1013 switch (addr)
1015 case _abs:
1016 pc=wval;
1017 break;
1018 case ind:
1019 pc=getmem(wval);
1020 pc|=256*getmem(wval+1);
1021 break;
1023 break;
1024 case jsr:
1025 push((pc+1)>>8);
1026 push((pc+1));
1027 wval=getmem(pc++);
1028 wval|=256*getmem(pc++);
1029 pc=wval;
1030 break;
1031 case lda:
1032 a=getaddr(addr);
1033 setflags(FLAG_Z,!a);
1034 setflags(FLAG_N,a&0x80);
1035 break;
1036 case ldx:
1037 x=getaddr(addr);
1038 setflags(FLAG_Z,!x);
1039 setflags(FLAG_N,x&0x80);
1040 break;
1041 case ldy:
1042 y=getaddr(addr);
1043 setflags(FLAG_Z,!y);
1044 setflags(FLAG_N,y&0x80);
1045 break;
1046 case lsr:
1047 bval=getaddr(addr); wval=(unsigned char)bval;
1048 wval>>=1;
1049 setaddr(addr,(unsigned char)wval);
1050 setflags(FLAG_Z,!wval);
1051 setflags(FLAG_N,wval&0x80);
1052 setflags(FLAG_C,bval&1);
1053 break;
1054 case _nop:
1055 break;
1056 case ora:
1057 bval=getaddr(addr);
1058 a|=bval;
1059 setflags(FLAG_Z,!a);
1060 setflags(FLAG_N,a&0x80);
1061 break;
1062 case pha:
1063 push(a);
1064 break;
1065 case php:
1066 push(p);
1067 break;
1068 case pla:
1069 a=pop();
1070 setflags(FLAG_Z,!a);
1071 setflags(FLAG_N,a&0x80);
1072 break;
1073 case plp:
1074 p=pop();
1075 break;
1076 case rol:
1077 bval=getaddr(addr);
1078 c=!!(p&FLAG_C);
1079 setflags(FLAG_C,bval&0x80);
1080 bval<<=1;
1081 bval|=c;
1082 setaddr(addr,bval);
1083 setflags(FLAG_N,bval&0x80);
1084 setflags(FLAG_Z,!bval);
1085 break;
1086 case ror:
1087 bval=getaddr(addr);
1088 c=!!(p&FLAG_C);
1089 setflags(FLAG_C,bval&1);
1090 bval>>=1;
1091 bval|=128*c;
1092 setaddr(addr,bval);
1093 setflags(FLAG_N,bval&0x80);
1094 setflags(FLAG_Z,!bval);
1095 break;
1096 case rti:
1097 /* Treat RTI like RTS */
1098 case rts:
1099 wval=pop();
1100 wval|=pop()<<8;
1101 pc=wval+1;
1102 break;
1103 case sbc:
1104 bval=getaddr(addr)^0xff;
1105 wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
1106 setflags(FLAG_C, wval&0x100);
1107 a=(unsigned char)wval;
1108 setflags(FLAG_Z, !a);
1109 setflags(FLAG_N, a>127);
1110 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
1111 break;
1112 case sec:
1113 setflags(FLAG_C,1);
1114 break;
1115 case sed:
1116 setflags(FLAG_D,1);
1117 break;
1118 case sei:
1119 setflags(FLAG_I,1);
1120 break;
1121 case sta:
1122 putaddr(addr,a);
1123 break;
1124 case stx:
1125 putaddr(addr,x);
1126 break;
1127 case sty:
1128 putaddr(addr,y);
1129 break;
1130 case tax:
1131 x=a;
1132 setflags(FLAG_Z, !x);
1133 setflags(FLAG_N, x&0x80);
1134 break;
1135 case tay:
1136 y=a;
1137 setflags(FLAG_Z, !y);
1138 setflags(FLAG_N, y&0x80);
1139 break;
1140 case tsx:
1141 x=s;
1142 setflags(FLAG_Z, !x);
1143 setflags(FLAG_N, x&0x80);
1144 break;
1145 case txa:
1146 a=x;
1147 setflags(FLAG_Z, !a);
1148 setflags(FLAG_N, a&0x80);
1149 break;
1150 case txs:
1151 s=x;
1152 break;
1153 case tya:
1154 a=y;
1155 setflags(FLAG_Z, !a);
1156 setflags(FLAG_N, a&0x80);
1157 break;
1161 void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1162 void cpuJSR(unsigned short npc, unsigned char na)
1164 a=na;
1165 x=0;
1166 y=0;
1167 p=0;
1168 s=255;
1169 pc=npc;
1170 push(0);
1171 push(0);
1173 while (pc > 1)
1174 cpuParse();
1178 void c64Init(int nSampleRate) ICODE_ATTR;
1179 void c64Init(int nSampleRate)
1181 synth_init(nSampleRate);
1182 memset(memory, 0, sizeof(memory));
1184 cpuReset();
1189 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1190 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size) ICODE_ATTR;
1191 unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1192 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
1194 unsigned char *pData;
1195 unsigned char data_file_offset;
1197 pData = (unsigned char*)pSidData;
1198 data_file_offset = pData[7];
1200 *load_addr = pData[8]<<8;
1201 *load_addr|= pData[9];
1203 *init_addr = pData[10]<<8;
1204 *init_addr|= pData[11];
1206 *play_addr = pData[12]<<8;
1207 *play_addr|= pData[13];
1209 *subsongs = pData[0xf]-1;
1210 *startsong = pData[0x11]-1;
1212 *load_addr = pData[data_file_offset];
1213 *load_addr|= pData[data_file_offset+1]<<8;
1215 *speed = pData[0x15];
1217 memset(memory, 0, sizeof(memory));
1218 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1220 if (*play_addr == 0)
1222 cpuJSR(*init_addr, 0);
1223 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1226 return *load_addr;
1229 static int nSamplesRendered = 0;
1230 static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1231 static int nSamplesToRender = 0;
1233 /* this is the codec entry point */
1234 enum codec_status codec_main(enum codec_entry_call_reason reason)
1236 if (reason == CODEC_LOAD) {
1237 /* Make use of 44.1khz */
1238 ci->configure(DSP_SWITCH_FREQUENCY, SAMPLE_RATE);
1239 /* Sample depth is 28 bit host endian */
1240 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1241 /* Mono output */
1242 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1245 return CODEC_OK;
1248 /* this is called for each file to process */
1249 enum codec_status codec_run(void)
1251 size_t filesize;
1252 unsigned short load_addr, init_addr, play_addr;
1253 unsigned char subSongsMax, subSong, song_speed;
1254 unsigned char *sidfile = NULL;
1255 intptr_t param;
1257 if (codec_init()) {
1258 return CODEC_ERROR;
1261 codec_set_replaygain(ci->id3);
1263 /* Load SID file the read_filebuf callback will return the full requested
1264 * size if at all possible, so there is no need to loop */
1265 ci->seek_buffer(0);
1266 sidfile = ci->request_buffer(&filesize, SID_BUFFER_SIZE);
1268 if (filesize == 0) {
1269 return CODEC_ERROR;
1272 c64Init(SAMPLE_RATE);
1273 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1274 &subSongsMax, &subSong, &song_speed, (unsigned short)filesize);
1275 sidPoke(24, 15); /* Turn on full volume */
1276 cpuJSR(init_addr, subSong); /* Start the song initialize */
1279 /* Set the elapsed time to the current subsong (in seconds) */
1280 ci->set_elapsed(subSong*1000);
1282 /* The main decoder loop */
1283 while (1) {
1284 enum codec_command_action action = ci->get_command(&param);
1286 if (action == CODEC_ACTION_HALT)
1287 break;
1289 if (action == CODEC_ACTION_SEEK_TIME) {
1290 /* New time is ready in param */
1292 /* Start playing from scratch */
1293 c64Init(SAMPLE_RATE);
1294 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1295 &subSongsMax, &subSong, &song_speed, (unsigned short)filesize);
1296 sidPoke(24, 15); /* Turn on full volume */
1297 subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
1298 cpuJSR(init_addr, subSong); /* Start the song initialize */
1299 nSamplesToRender = 0; /* Start the rendering from scratch */
1301 /* Set the elapsed time to the current subsong (in seconds) */
1302 ci->seek_complete();
1303 ci->set_elapsed(subSong*1000);
1306 nSamplesRendered = 0;
1307 while (nSamplesRendered < CHUNK_SIZE)
1309 if (nSamplesToRender == 0)
1311 cpuJSR(play_addr, 0);
1313 /* Find out if cia timing is used and how many samples
1314 have to be calculated for each cpujsr */
1315 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
1316 if ((nRefreshCIA==0) || (song_speed == 0))
1317 nRefreshCIA = 20000;
1318 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1320 nSamplesToRender = nSamplesPerCall;
1322 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1324 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1325 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1326 nSamplesRendered = CHUNK_SIZE;
1328 else
1330 synth_render(samples+nSamplesRendered, nSamplesToRender);
1331 nSamplesRendered += nSamplesToRender;
1332 nSamplesToRender = 0;
1336 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1339 return CODEC_OK;