1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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
31 *****************************/
33 /*********************
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
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
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 **************************/
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
;
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 */
115 unsigned short pulse
;
120 unsigned char ffreqlo
;
121 unsigned char ffreqhi
;
122 unsigned char res_ftv
;
123 unsigned char ftp_vol
;
126 /* internal oscillator def */
131 unsigned char filter
;
132 unsigned long attack
;
134 unsigned long sustain
;
135 unsigned long release
;
136 unsigned long counter
;
138 unsigned char envphase
;
139 unsigned long noisepos
;
140 unsigned long noiseval
;
141 unsigned char noiseout
;
144 /* internal filter def */
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
)
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
)
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
))
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) {
297 if (sample_nibble
< 0) {
304 if (sample_position
> sample_end
)
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;
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
)
331 mixing_frequency
= mixfrq
;
333 freqmul
= 15872000 / mixfrq
;
334 filtmul
= quickfloat_ConvertFromFloat(21.5332031f
)/mixfrq
;
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
)
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) */
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
;
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 */
389 /* now render the buffer */
390 for (bp
=0;bp
<len
;bp
++) {
395 /* step 2 : generate the two output signals (for filtered and non-
396 filtered) from the osc/eg sections */
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) {
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)
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)
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;
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;
471 case 2 : { /* Phase 2 : Sustain */
472 if ((signed int) osc
[v
].envval
!= (signed int) (osc
[v
].sustain
<<16))
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 :) */
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 :) */
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
)
501 outf
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
503 outo
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
507 /* Don't use filters, just mix all voices together */
508 outf
+=((signed short)(outv
-0x80)) * (osc
[v
].envval
>>4);
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
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
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
);
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;
540 *(buffer
+bp
) = GenerateDigi(outf
)<<3;
550 static inline unsigned char getmem(unsigned short 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 */
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
;
597 case 0xfd: sample_active
= 0; break;
599 case 0xff: sample_active
= 1; 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
)
617 if ((reg
>= 7) && (reg
<=13)) {voice
=1; reg
-=7;}
618 else if ((reg
>= 14) && (reg
<=20)) {voice
=2; reg
-=14;}
621 case 0: { /* Set frequency: Low byte */
622 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff00)+val
;
625 case 1: { /* Set frequency: High byte */
626 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff)+(val
<<8);
629 case 2: { /* Set pulse width: Low byte */
630 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff00)+val
;
633 case 3: { /* Set pulse width: High byte */
634 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff)+(val
<<8);
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;
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;}
658 static inline unsigned char getaddr(int mode
)
660 unsigned short ad
,ad2
;
669 ad
|=256*getmem(pc
++);
673 ad
|=256*getmem(pc
++);
678 ad
|=256*getmem(pc
++);
687 return getmem(ad
&0xff);
691 return getmem(ad
&0xff);
697 ad2
|=getmem(ad
&0xff)<<8;
702 ad2
|=getmem((ad
+1)&0xff)<<8;
711 static inline void setaddr(int mode
, unsigned char val
)
713 unsigned short ad
,ad2
;
718 ad
|=256*getmem(pc
-1);
723 ad
|=256*getmem(pc
-1);
743 static inline void putaddr(int mode
, unsigned char val
)
745 unsigned short ad
,ad2
;
784 ad2
|=getmem(ad
&0xff)<<8;
790 ad2
|=getmem((ad
+1)&0xff)<<8;
801 static inline void setflags(int flag
, int cond
)
808 static inline void push(unsigned char val
)
814 static inline unsigned char pop(void)
817 return getmem(0x100+s
);
820 static inline void branch(int flag
)
823 dist
=(signed char)getaddr(imm
);
828 void cpuReset(void) ICODE_ATTR
;
837 void cpuResetTo(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
838 void cpuResetTo(unsigned short npc
, unsigned char na
)
848 static inline void cpuParse(void)
850 unsigned char opc
=getmem(pc
++);
851 int cmd
=opcodes
[opc
];
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
)));
867 setflags(FLAG_Z
, !a
);
868 setflags(FLAG_N
, a
&0x80);
873 setaddr(addr
,(unsigned char)wval
);
874 setflags(FLAG_Z
,!wval
);
875 setflags(FLAG_N
,wval
&0x80);
876 setflags(FLAG_C
,wval
&0x100);
904 setflags(FLAG_Z
,!(a
&bval
));
905 setflags(FLAG_N
,bval
&0x80);
906 setflags(FLAG_V
,bval
&0x40);
909 pc
=0; /* Just quit the emulation */
925 wval
=(unsigned short)a
-bval
;
926 setflags(FLAG_Z
,!wval
);
927 setflags(FLAG_N
,wval
&0x80);
928 setflags(FLAG_C
,a
>=bval
);
932 wval
=(unsigned short)x
-bval
;
933 setflags(FLAG_Z
,!wval
);
934 setflags(FLAG_N
,wval
&0x80);
935 setflags(FLAG_C
,x
>=bval
);
939 wval
=(unsigned short)y
-bval
;
940 setflags(FLAG_Z
,!wval
);
941 setflags(FLAG_N
,wval
&0x80);
942 setflags(FLAG_C
,y
>=bval
);
948 setflags(FLAG_Z
,!bval
);
949 setflags(FLAG_N
,bval
&0x80);
954 setflags(FLAG_N
,x
&0x80);
959 setflags(FLAG_N
,y
&0x80);
965 setflags(FLAG_N
,a
&0x80);
971 setflags(FLAG_Z
,!bval
);
972 setflags(FLAG_N
,bval
&0x80);
977 setflags(FLAG_N
,x
&0x80);
982 setflags(FLAG_N
,y
&0x80);
986 wval
|=256*getmem(pc
++);
994 pc
|=256*getmem(wval
+1);
1002 wval
|=256*getmem(pc
++);
1007 setflags(FLAG_Z
,!a
);
1008 setflags(FLAG_N
,a
&0x80);
1012 setflags(FLAG_Z
,!x
);
1013 setflags(FLAG_N
,x
&0x80);
1017 setflags(FLAG_Z
,!y
);
1018 setflags(FLAG_N
,y
&0x80);
1021 bval
=getaddr(addr
); wval
=(unsigned char)bval
;
1023 setaddr(addr
,(unsigned char)wval
);
1024 setflags(FLAG_Z
,!wval
);
1025 setflags(FLAG_N
,wval
&0x80);
1026 setflags(FLAG_C
,bval
&1);
1033 setflags(FLAG_Z
,!a
);
1034 setflags(FLAG_N
,a
&0x80);
1044 setflags(FLAG_Z
,!a
);
1045 setflags(FLAG_N
,a
&0x80);
1053 setflags(FLAG_C
,bval
&0x80);
1057 setflags(FLAG_N
,bval
&0x80);
1058 setflags(FLAG_Z
,!bval
);
1063 setflags(FLAG_C
,bval
&1);
1067 setflags(FLAG_N
,bval
&0x80);
1068 setflags(FLAG_Z
,!bval
);
1071 /* Treat RTI like RTS */
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
)));
1106 setflags(FLAG_Z
, !x
);
1107 setflags(FLAG_N
, x
&0x80);
1111 setflags(FLAG_Z
, !y
);
1112 setflags(FLAG_N
, y
&0x80);
1116 setflags(FLAG_Z
, !x
);
1117 setflags(FLAG_N
, x
&0x80);
1121 setflags(FLAG_Z
, !a
);
1122 setflags(FLAG_N
, a
&0x80);
1129 setflags(FLAG_Z
, !a
);
1130 setflags(FLAG_N
, a
&0x80);
1135 void cpuJSR(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
1136 void cpuJSR(unsigned short npc
, unsigned char na
)
1152 void c64Init(int nSampleRate
) ICODE_ATTR
;
1153 void c64Init(int nSampleRate
)
1155 synth_init(nSampleRate
);
1156 memset(memory
, 0, sizeof(memory
));
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];
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);
1216 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
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
;
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 */
1239 filesize
= ci
->read_filebuf(sidfile
, sizeof(sidfile
));
1241 if (filesize
== 0) {
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 */
1257 enum codec_command_action action
= ci
->get_command(¶m
);
1259 if (action
== CODEC_ACTION_HALT
)
1262 if (action
== CODEC_ACTION_SEEK_TIME
) {
1263 /* New time is ready in param */
1265 /* Start playing from scratch */
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
;
1303 synth_render(samples
+nSamplesRendered
, nSamplesToRender
);
1304 nSamplesRendered
+= nSamplesToRender
;
1305 nSamplesToRender
= 0;
1309 ci
->pcmbuf_insert(samples
, NULL
, CHUNK_SIZE
);