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 * All files in this archive are subject to the GNU General Public License.
17 * See the file COPYING in the source tree root for full license agreement.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 /*****************************
25 * kb explicitly points out that this emulation sounds crappy, though
26 * we decided to put it open source so everyone can enjoy sidmusic
29 *****************************/
31 /*********************
33 * Added 16-04-2006: Rainer Sinsch
34 * Removed all time critical floating point operations and
35 * replaced them with quick & dirty integer calculations
37 * Added 17-04-2006: Rainer Sinsch
38 * Improved quick & dirty integer calculations for the resonant filter
39 * Improved audio quality by 4 bits
42 * Added 17-04-2006: Dave Chapman
43 * Improved file loading
45 * Added 17-04-2006: Rainer Sinsch
46 * Added sample routines
47 * Added cia timing routines
48 * Added fast forwarding capabilities
49 * Corrected bug in sid loading
52 * Added 04-05-2006: Rainer Sinsch
53 * Implemented Marco Alanens suggestion for subsong selection:
54 * Select the subsong by seeking: Each second represents a subsong
56 **************************/
66 #define CHUNK_SIZE (1024*2)
68 /* This codec supports SID Files:
72 static int32_t samples
[CHUNK_SIZE
] IBSS_ATTR
; /* The sample buffer */
74 /* Static buffer for the plain SID-File */
75 static unsigned char sidfile
[0x10000];
77 void sidPoke(int reg
, unsigned char val
) ICODE_ATTR
;
102 adc
, _and
, asl
, bcc
, bcs
, beq
, bit
, bmi
, bne
, bpl
, brk
, bvc
, bvs
, clc
,
103 cld
, cli
, clv
, cmp
, cpx
, cpy
, dec
, dex
, dey
, eor
, inc
, inx
, iny
, jmp
,
104 jsr
, lda
, ldx
, ldy
, lsr
, _nop
, ora
, pha
, php
, pla
, plp
, rol
, ror
, rti
,
105 rts
, sbc
, sec
, sed
, sei
, sta
, stx
, sty
, tax
, tay
, tsx
, txa
, txs
, tya
,
109 /* SID register definition */
113 unsigned short pulse
;
118 unsigned char ffreqlo
;
119 unsigned char ffreqhi
;
120 unsigned char res_ftv
;
121 unsigned char ftp_vol
;
124 /* internal oscillator def */
129 unsigned char filter
;
130 unsigned long attack
;
132 unsigned long sustain
;
133 unsigned long release
;
134 unsigned long counter
;
136 unsigned char envphase
;
137 unsigned long noisepos
;
138 unsigned long noiseval
;
139 unsigned char noiseout
;
142 /* internal filter def */
156 /* ------------------------ pseudo-constants (depending on mixing freq) */
157 int mixing_frequency IDATA_ATTR
;
158 unsigned long freqmul IDATA_ATTR
;
159 int filtmul IDATA_ATTR
;
160 unsigned long attacks
[16] IDATA_ATTR
;
161 unsigned long releases
[16] IDATA_ATTR
;
163 /* ------------------------------------------------------------ globals */
164 struct s6581 sid IDATA_ATTR
;
165 struct sidosc osc
[3] IDATA_ATTR
;
166 struct sidflt filter IDATA_ATTR
;
168 /* ------------------------------------------------------ C64 Emu Stuff */
169 unsigned char bval IDATA_ATTR
;
170 unsigned short wval IDATA_ATTR
;
171 /* -------------------------------------------------- Register & memory */
172 unsigned char a
,x
,y
,s
,p IDATA_ATTR
;
173 unsigned short pc IDATA_ATTR
;
175 unsigned char memory
[65536];
177 /* ----------------------------------------- Variables for sample stuff */
178 static int sample_active IDATA_ATTR
;
179 static int sample_position
, sample_start
, sample_end
, sample_repeat_start IDATA_ATTR
;
180 static int fracPos IDATA_ATTR
; /* Fractal position of sample */
181 static int sample_period IDATA_ATTR
;
182 static int sample_repeats IDATA_ATTR
;
183 static int sample_order IDATA_ATTR
;
184 static int sample_nibble IDATA_ATTR
;
186 static int internal_period
, internal_order
, internal_start
, internal_end
,
187 internal_add
, internal_repeat_times
, internal_repeat_start IDATA_ATTR
;
189 /* ---------------------------------------------------------- constants */
190 static const float attackTimes
[16] ICONST_ATTR
=
192 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
193 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
194 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
195 0.977715461, 2.93364701, 4.88907793, 7.82272493
197 static const float decayReleaseTimes
[16] ICONST_ATTR
=
199 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
200 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
201 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
204 static const int opcodes
[256] ICONST_ATTR
= {
205 brk
,ora
,xxx
,xxx
,xxx
,ora
,asl
,xxx
,php
,ora
,asl
,xxx
,xxx
,ora
,asl
,xxx
,
206 bpl
,ora
,xxx
,xxx
,xxx
,ora
,asl
,xxx
,clc
,ora
,xxx
,xxx
,xxx
,ora
,asl
,xxx
,
207 jsr
,_and
,xxx
,xxx
,bit
,_and
,rol
,xxx
,plp
,_and
,rol
,xxx
,bit
,_and
,rol
,xxx
,
208 bmi
,_and
,xxx
,xxx
,xxx
,_and
,rol
,xxx
,sec
,_and
,xxx
,xxx
,xxx
,_and
,rol
,xxx
,
209 rti
,eor
,xxx
,xxx
,xxx
,eor
,lsr
,xxx
,pha
,eor
,lsr
,xxx
,jmp
,eor
,lsr
,xxx
,
210 bvc
,eor
,xxx
,xxx
,xxx
,eor
,lsr
,xxx
,cli
,eor
,xxx
,xxx
,xxx
,eor
,lsr
,xxx
,
211 rts
,adc
,xxx
,xxx
,xxx
,adc
,ror
,xxx
,pla
,adc
,ror
,xxx
,jmp
,adc
,ror
,xxx
,
212 bvs
,adc
,xxx
,xxx
,xxx
,adc
,ror
,xxx
,sei
,adc
,xxx
,xxx
,xxx
,adc
,ror
,xxx
,
213 xxx
,sta
,xxx
,xxx
,sty
,sta
,stx
,xxx
,dey
,xxx
,txa
,xxx
,sty
,sta
,stx
,xxx
,
214 bcc
,sta
,xxx
,xxx
,sty
,sta
,stx
,xxx
,tya
,sta
,txs
,xxx
,xxx
,sta
,xxx
,xxx
,
215 ldy
,lda
,ldx
,xxx
,ldy
,lda
,ldx
,xxx
,tay
,lda
,tax
,xxx
,ldy
,lda
,ldx
,xxx
,
216 bcs
,lda
,xxx
,xxx
,ldy
,lda
,ldx
,xxx
,clv
,lda
,tsx
,xxx
,ldy
,lda
,ldx
,xxx
,
217 cpy
,cmp
,xxx
,xxx
,cpy
,cmp
,dec
,xxx
,iny
,cmp
,dex
,xxx
,cpy
,cmp
,dec
,xxx
,
218 bne
,cmp
,xxx
,xxx
,xxx
,cmp
,dec
,xxx
,cld
,cmp
,xxx
,xxx
,xxx
,cmp
,dec
,xxx
,
219 cpx
,sbc
,xxx
,xxx
,cpx
,sbc
,inc
,xxx
,inx
,sbc
,_nop
,xxx
,cpx
,sbc
,inc
,xxx
,
220 beq
,sbc
,xxx
,xxx
,xxx
,sbc
,inc
,xxx
,sed
,sbc
,xxx
,xxx
,xxx
,sbc
,inc
,xxx
224 static const int modes
[256] ICONST_ATTR
= {
225 imp
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
226 rel
,indy
,xxx
,xxx
,xxx
,zpx
,zpx
,xxx
,imp
,absy
,xxx
,xxx
,xxx
,absx
,absx
,xxx
,
227 _abs
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
228 rel
,indy
,xxx
,xxx
,xxx
,zpx
,zpx
,xxx
,imp
,absy
,xxx
,xxx
,xxx
,absx
,absx
,xxx
,
229 imp
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
230 rel
,indy
,xxx
,xxx
,xxx
,zpx
,zpx
,xxx
,imp
,absy
,xxx
,xxx
,xxx
,absx
,absx
,xxx
,
231 imp
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,ind
,_abs
,_abs
,xxx
,
232 rel
,indy
,xxx
,xxx
,xxx
,zpx
,zpx
,xxx
,imp
,absy
,xxx
,xxx
,xxx
,absx
,absx
,xxx
,
233 imm
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
234 rel
,indy
,xxx
,xxx
,zpx
,zpx
,zpy
,xxx
,imp
,absy
,acc
,xxx
,xxx
,absx
,absx
,xxx
,
235 imm
,indx
,imm
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
236 rel
,indy
,xxx
,xxx
,zpx
,zpx
,zpy
,xxx
,imp
,absy
,acc
,xxx
,absx
,absx
,absy
,xxx
,
237 imm
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
238 rel
,indy
,xxx
,xxx
,zpx
,zpx
,zpx
,xxx
,imp
,absy
,acc
,xxx
,xxx
,absx
,absx
,xxx
,
239 imm
,indx
,xxx
,xxx
,zp
,zp
,zp
,xxx
,imp
,imm
,acc
,xxx
,_abs
,_abs
,_abs
,xxx
,
240 rel
,indy
,xxx
,xxx
,zpx
,zpx
,zpx
,xxx
,imp
,absy
,acc
,xxx
,xxx
,absx
,absx
,xxx
243 /* Routines for quick & dirty float calculation */
245 static inline int quickfloat_ConvertFromInt(int i
)
249 static inline int quickfloat_ConvertFromFloat(float f
)
251 return (int)(f
*(1<<16));
253 static inline int quickfloat_Multiply(int a
, int b
)
255 return (a
>>8)*(b
>>8);
257 static inline int quickfloat_ConvertToInt(int i
)
262 /* Get the bit from an unsigned long at a specified position */
263 static inline unsigned char get_bit(unsigned long val
, unsigned char b
)
265 return (unsigned char) ((val
>> b
) & 1);
269 static inline int GenerateDigi(int sIn
)
271 static int last_sample
= 0;
272 static int sample
= 0;
274 if (!sample_active
) return(sIn
);
276 if ((sample_position
< sample_end
) && (sample_position
>= sample_start
))
280 fracPos
+= 985248/sample_period
;
282 if (fracPos
> mixing_frequency
)
284 fracPos
%=mixing_frequency
;
286 last_sample
= sample
;
288 // N�hstes Samples holen
289 if (sample_order
== 0) {
290 sample_nibble
++; // Nähstes Sample-Nibble
291 if (sample_nibble
==2) {
298 if (sample_nibble
< 0) {
305 if (sample_position
> sample_end
)
308 sample_position
= sample_repeat_start
;
310 else sample_active
= 0;
313 sample
= memory
[sample_position
&0xffff];
314 if (sample_nibble
==1) // Hi-Nibble holen?
315 sample
= (sample
& 0xf0)>>4;
316 else sample
= sample
& 0x0f;
326 /* ------------------------------------------------------------- synthesis
327 initialize SID and frequency dependant values */
328 void synth_init(unsigned long mixfrq
) ICODE_ATTR
;
329 void synth_init(unsigned long mixfrq
)
332 mixing_frequency
= mixfrq
;
334 freqmul
= 15872000 / mixfrq
;
335 filtmul
= quickfloat_ConvertFromFloat(21.5332031f
)/mixfrq
;
337 attacks
[i
]=(int) (0x1000000 / (attackTimes
[i
]*mixfrq
));
338 releases
[i
]=(int) (0x1000000 / (decayReleaseTimes
[i
]*mixfrq
));
340 memset(&sid
,0,sizeof(sid
));
341 memset(osc
,0,sizeof(osc
));
342 memset(&filter
,0,sizeof(filter
));
343 osc
[0].noiseval
= 0xffffff;
344 osc
[1].noiseval
= 0xffffff;
345 osc
[2].noiseval
= 0xffffff;
348 /* render a buffer of n samples with the actual register contents */
349 void synth_render (int32_t *buffer
, unsigned long len
) ICODE_ATTR
;
350 void synth_render (int32_t *buffer
, unsigned long len
)
353 /* step 1: convert the not easily processable sid registers into some
354 more convenient and fast values (makes the thing much faster
355 if you process more than 1 sample value at once) */
358 osc
[v
].pulse
= (sid
.v
[v
].pulse
& 0xfff) << 16;
359 osc
[v
].filter
= get_bit(sid
.res_ftv
,v
);
360 osc
[v
].attack
= attacks
[sid
.v
[v
].ad
>> 4];
361 osc
[v
].decay
= releases
[sid
.v
[v
].ad
& 0xf];
362 osc
[v
].sustain
= sid
.v
[v
].sr
& 0xf0;
363 osc
[v
].release
= releases
[sid
.v
[v
].sr
& 0xf];
364 osc
[v
].wave
= sid
.v
[v
].wave
;
365 osc
[v
].freq
= ((unsigned long)sid
.v
[v
].freq
)*freqmul
;
369 filter
.freq
= (16*sid
.ffreqhi
+ (sid
.ffreqlo
&0x7)) * filtmul
;
371 if (filter
.freq
>quickfloat_ConvertFromInt(1))
372 filter
.freq
=quickfloat_ConvertFromInt(1);
373 /* the above line isnt correct at all - the problem is that the filter
374 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
375 for 32KHz and lower - well, but sound quality is bad enough then to
376 neglect the fact that the filter doesnt come that high ;) */
377 filter
.l_ena
= get_bit(sid
.ftp_vol
,4);
378 filter
.b_ena
= get_bit(sid
.ftp_vol
,5);
379 filter
.h_ena
= get_bit(sid
.ftp_vol
,6);
380 filter
.v3ena
= !get_bit(sid
.ftp_vol
,7);
381 filter
.vol
= (sid
.ftp_vol
& 0xf);
382 filter
.rez
= quickfloat_ConvertFromFloat(1.2f
) -
383 quickfloat_ConvertFromFloat(0.04f
)*(sid
.res_ftv
>> 4);
385 /* We precalculate part of the quick float operation, saves time in loop later */
390 /* now render the buffer */
391 for (bp
=0;bp
<len
;bp
++) {
396 /* step 2 : generate the two output signals (for filtered and non-
397 filtered) from the osc/eg sections */
399 /* update wave counter */
400 osc
[v
].counter
= (osc
[v
].counter
+osc
[v
].freq
) & 0xFFFFFFF;
401 /* reset counter / noise generator if reset get_bit set */
402 if (osc
[v
].wave
& 0x08) {
405 osc
[v
].noiseval
= 0xffffff;
407 unsigned char refosc
= v
?v
-1:2; /* reference oscillator for sync/ring */
408 /* sync oscillator to refosc if sync bit set */
409 if (osc
[v
].wave
& 0x02)
410 if (osc
[refosc
].counter
< osc
[refosc
].freq
)
411 osc
[v
].counter
= osc
[refosc
].counter
* osc
[v
].freq
/ osc
[refosc
].freq
;
412 /* generate waveforms with really simple algorithms */
413 unsigned char triout
= (unsigned char) (osc
[v
].counter
>>19);
414 if (osc
[v
].counter
>>27)
416 unsigned char sawout
= (unsigned char) (osc
[v
].counter
>> 20);
417 unsigned char plsout
= (unsigned char) ((osc
[v
].counter
> osc
[v
].pulse
)-1);
419 /* generate noise waveform exactly as the SID does. */
420 if (osc
[v
].noisepos
!=(osc
[v
].counter
>>23))
422 osc
[v
].noisepos
= osc
[v
].counter
>> 23;
423 osc
[v
].noiseval
= (osc
[v
].noiseval
<< 1) |
424 (get_bit(osc
[v
].noiseval
,22) ^ get_bit(osc
[v
].noiseval
,17));
425 osc
[v
].noiseout
= (get_bit(osc
[v
].noiseval
,22) << 7) |
426 (get_bit(osc
[v
].noiseval
,20) << 6) |
427 (get_bit(osc
[v
].noiseval
,16) << 5) |
428 (get_bit(osc
[v
].noiseval
,13) << 4) |
429 (get_bit(osc
[v
].noiseval
,11) << 3) |
430 (get_bit(osc
[v
].noiseval
, 7) << 2) |
431 (get_bit(osc
[v
].noiseval
, 4) << 1) |
432 (get_bit(osc
[v
].noiseval
, 2) << 0);
434 unsigned char nseout
= osc
[v
].noiseout
;
436 /* modulate triangle wave if ringmod bit set */
437 if (osc
[v
].wave
& 0x04)
438 if (osc
[refosc
].counter
< 0x8000000)
441 /* now mix the oscillators with an AND operation as stated in
442 the SID's reference manual - even if this is completely wrong.
443 well, at least, the $30 and $70 waveform sounds correct and there's
444 no real solution to do $50 and $60, so who cares. */
446 unsigned char outv
=0xFF;
447 if (osc
[v
].wave
& 0x10) outv
&= triout
;
448 if (osc
[v
].wave
& 0x20) outv
&= sawout
;
449 if (osc
[v
].wave
& 0x40) outv
&= plsout
;
450 if (osc
[v
].wave
& 0x80) outv
&= nseout
;
452 /* so now process the volume according to the phase and adsr values */
453 switch (osc
[v
].envphase
) {
454 case 0 : { /* Phase 0 : Attack */
455 osc
[v
].envval
+=osc
[v
].attack
;
456 if (osc
[v
].envval
>= 0xFFFFFF)
458 osc
[v
].envval
= 0xFFFFFF;
463 case 1 : { /* Phase 1 : Decay */
464 osc
[v
].envval
-=osc
[v
].decay
;
465 if ((signed int) osc
[v
].envval
<= (signed int) (osc
[v
].sustain
<<16))
467 osc
[v
].envval
= osc
[v
].sustain
<<16;
472 case 2 : { /* Phase 2 : Sustain */
473 if ((signed int) osc
[v
].envval
!= (signed int) (osc
[v
].sustain
<<16))
477 /* :) yes, thats exactly how the SID works. and maybe
478 a music routine out there supports this, so better
479 let it in, thanks :) */
482 case 3 : { /* Phase 3 : Release */
483 osc
[v
].envval
-=osc
[v
].release
;
484 if (osc
[v
].envval
< 0x40000) osc
[v
].envval
= 0x40000;
486 /* the volume offset is because the SID does not
487 completely silence the voices when it should. most
488 emulators do so though and thats the main reason
489 why the sound of emulators is too, err... emulated :) */
496 /* now route the voice output to either the non-filtered or the
497 filtered channel and dont forget to blank out osc3 if desired */
499 if (v
<2 || filter
.v3ena
)
502 outf
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
504 outo
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
508 /* Don't use filters, just mix all voices together */
509 outf
+=((signed short)(outv
-0x80)) * (osc
[v
].envval
>>4);
516 * so, now theres finally time to apply the multi-mode resonant filter
517 * to the signal. The easiest thing ist just modelling a real electronic
518 * filter circuit instead of fiddling around with complex IIRs or even
520 * it sounds as good as them or maybe better and needs only 3 MULs and
521 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
522 * Mage messed the whole thing completely up - as the rest of the
524 * This filter sounds a lot like the 8580, as the low-quality, dirty
525 * sound of the 6581 is uuh too hard to achieve :) */
527 filter
.h
= quickfloat_ConvertFromInt(outf
) - (filter
.b
>>8)*filter
.rez
- filter
.l
;
528 filter
.b
+= quickfloat_Multiply(filter
.freq
, filter
.h
);
529 filter
.l
+= quickfloat_Multiply(filter
.freq
, filter
.b
);
533 if (filter
.l_ena
) outf
+=quickfloat_ConvertToInt(filter
.l
);
534 if (filter
.b_ena
) outf
+=quickfloat_ConvertToInt(filter
.b
);
535 if (filter
.h_ena
) outf
+=quickfloat_ConvertToInt(filter
.h
);
537 int final_sample
= (filter
.vol
*(outo
+outf
));
538 *(buffer
+bp
)= GenerateDigi(final_sample
)<<13;
541 *(buffer
+bp
) = GenerateDigi(outf
)<<3;
551 static inline unsigned char getmem(unsigned short addr
)
556 static inline void setmem(unsigned short addr
, unsigned char value
)
558 if ((addr
&0xfc00)==0xd400)
560 sidPoke(addr
&0x1f,value
);
561 /* New SID-Register */
566 case 0xd41f: /* Start-Hi */
567 internal_start
= (internal_start
&0x00ff) | (value
<<8); break;
568 case 0xd41e: /* Start-Lo */
569 internal_start
= (internal_start
&0xff00) | (value
); break;
570 case 0xd47f: /* Repeat-Hi */
571 internal_repeat_start
= (internal_repeat_start
&0x00ff) | (value
<<8); break;
572 case 0xd47e: /* Repeat-Lo */
573 internal_repeat_start
= (internal_repeat_start
&0xff00) | (value
); break;
574 case 0xd43e: /* End-Hi */
575 internal_end
= (internal_end
&0x00ff) | (value
<<8); break;
576 case 0xd43d: /* End-Lo */
577 internal_end
= (internal_end
&0xff00) | (value
); break;
578 case 0xd43f: /* Loop-Size */
579 internal_repeat_times
= value
; break;
580 case 0xd45e: /* Period-Hi */
581 internal_period
= (internal_period
&0x00ff) | (value
<<8); break;
582 case 0xd45d: /* Period-Lo */
583 internal_period
= (internal_period
&0xff00) | (value
); break;
584 case 0xd47d: /* Sample Order */
585 internal_order
= value
; break;
586 case 0xd45f: /* Sample Add */
587 internal_add
= value
; break;
588 case 0xd41d: /* Start sampling */
589 sample_repeats
= internal_repeat_times
;
590 sample_position
= internal_start
;
591 sample_start
= internal_start
;
592 sample_end
= internal_end
;
593 sample_repeat_start
= internal_repeat_start
;
594 sample_period
= internal_period
;
595 sample_order
= internal_order
;
598 case 0xfd: sample_active
= 0; break;
600 case 0xff: sample_active
= 1; break;
607 else memory
[addr
]=value
;
611 * Poke a value into the sid register
613 void sidPoke(int reg
, unsigned char val
) ICODE_ATTR
;
614 void sidPoke(int reg
, unsigned char val
)
618 if ((reg
>= 7) && (reg
<=13)) {voice
=1; reg
-=7;}
619 else if ((reg
>= 14) && (reg
<=20)) {voice
=2; reg
-=14;}
622 case 0: { /* Set frequency: Low byte */
623 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff00)+val
;
626 case 1: { /* Set frequency: High byte */
627 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff)+(val
<<8);
630 case 2: { /* Set pulse width: Low byte */
631 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff00)+val
;
634 case 3: { /* Set pulse width: High byte */
635 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff)+(val
<<8);
638 case 4: { sid
.v
[voice
].wave
= val
;
639 /* Directly look at GATE-Bit!
640 * a change may happen twice or more often during one cpujsr
641 * Put the Envelope Generator into attack or release phase if desired
643 if ((val
& 0x01) == 0) osc
[voice
].envphase
=3;
644 else if (osc
[voice
].envphase
==3) osc
[voice
].envphase
=0;
648 case 5: { sid
.v
[voice
].ad
= val
; break;}
649 case 6: { sid
.v
[voice
].sr
= val
; break;}
651 case 21: { sid
.ffreqlo
= val
; break; }
652 case 22: { sid
.ffreqhi
= val
; break; }
653 case 23: { sid
.res_ftv
= val
; break; }
654 case 24: { sid
.ftp_vol
= val
; break;}
659 static inline unsigned char getaddr(int mode
)
661 unsigned short ad
,ad2
;
670 ad
|=256*getmem(pc
++);
674 ad
|=256*getmem(pc
++);
679 ad
|=256*getmem(pc
++);
688 return getmem(ad
&0xff);
692 return getmem(ad
&0xff);
698 ad2
|=getmem(ad
&0xff)<<8;
703 ad2
|=getmem((ad
+1)&0xff)<<8;
712 static inline void setaddr(int mode
, unsigned char val
)
714 unsigned short ad
,ad2
;
719 ad
|=256*getmem(pc
-1);
724 ad
|=256*getmem(pc
-1);
744 static inline void putaddr(int mode
, unsigned char val
)
746 unsigned short ad
,ad2
;
785 ad2
|=getmem(ad
&0xff)<<8;
791 ad2
|=getmem((ad
+1)&0xff)<<8;
802 static inline void setflags(int flag
, int cond
)
809 static inline void push(unsigned char val
)
815 static inline unsigned char pop(void)
818 return getmem(0x100+s
);
821 static inline void branch(int flag
)
824 dist
=(signed char)getaddr(imm
);
829 void cpuReset(void) ICODE_ATTR
;
838 void cpuResetTo(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
839 void cpuResetTo(unsigned short npc
, unsigned char na
)
849 static inline void cpuParse(void)
851 unsigned char opc
=getmem(pc
++);
852 int cmd
=opcodes
[opc
];
858 wval
=(unsigned short)a
+getaddr(addr
)+((p
&FLAG_C
)?1:0);
859 setflags(FLAG_C
, wval
&0x100);
860 a
=(unsigned char)wval
;
861 setflags(FLAG_Z
, !a
);
862 setflags(FLAG_N
, a
&0x80);
863 setflags(FLAG_V
, (!!(p
&FLAG_C
)) ^ (!!(p
&FLAG_N
)));
868 setflags(FLAG_Z
, !a
);
869 setflags(FLAG_N
, a
&0x80);
874 setaddr(addr
,(unsigned char)wval
);
875 setflags(FLAG_Z
,!wval
);
876 setflags(FLAG_N
,wval
&0x80);
877 setflags(FLAG_C
,wval
&0x100);
905 setflags(FLAG_Z
,!(a
&bval
));
906 setflags(FLAG_N
,bval
&0x80);
907 setflags(FLAG_V
,bval
&0x40);
910 pc
=0; /* Just quit the emulation */
926 wval
=(unsigned short)a
-bval
;
927 setflags(FLAG_Z
,!wval
);
928 setflags(FLAG_N
,wval
&0x80);
929 setflags(FLAG_C
,a
>=bval
);
933 wval
=(unsigned short)x
-bval
;
934 setflags(FLAG_Z
,!wval
);
935 setflags(FLAG_N
,wval
&0x80);
936 setflags(FLAG_C
,x
>=bval
);
940 wval
=(unsigned short)y
-bval
;
941 setflags(FLAG_Z
,!wval
);
942 setflags(FLAG_N
,wval
&0x80);
943 setflags(FLAG_C
,y
>=bval
);
949 setflags(FLAG_Z
,!bval
);
950 setflags(FLAG_N
,bval
&0x80);
955 setflags(FLAG_N
,x
&0x80);
960 setflags(FLAG_N
,y
&0x80);
966 setflags(FLAG_N
,a
&0x80);
972 setflags(FLAG_Z
,!bval
);
973 setflags(FLAG_N
,bval
&0x80);
978 setflags(FLAG_N
,x
&0x80);
983 setflags(FLAG_N
,y
&0x80);
987 wval
|=256*getmem(pc
++);
995 pc
|=256*getmem(wval
+1);
1003 wval
|=256*getmem(pc
++);
1008 setflags(FLAG_Z
,!a
);
1009 setflags(FLAG_N
,a
&0x80);
1013 setflags(FLAG_Z
,!x
);
1014 setflags(FLAG_N
,x
&0x80);
1018 setflags(FLAG_Z
,!y
);
1019 setflags(FLAG_N
,y
&0x80);
1022 bval
=getaddr(addr
); wval
=(unsigned char)bval
;
1024 setaddr(addr
,(unsigned char)wval
);
1025 setflags(FLAG_Z
,!wval
);
1026 setflags(FLAG_N
,wval
&0x80);
1027 setflags(FLAG_C
,bval
&1);
1034 setflags(FLAG_Z
,!a
);
1035 setflags(FLAG_N
,a
&0x80);
1045 setflags(FLAG_Z
,!a
);
1046 setflags(FLAG_N
,a
&0x80);
1054 setflags(FLAG_C
,bval
&0x80);
1058 setflags(FLAG_N
,bval
&0x80);
1059 setflags(FLAG_Z
,!bval
);
1064 setflags(FLAG_C
,bval
&1);
1068 setflags(FLAG_N
,bval
&0x80);
1069 setflags(FLAG_Z
,!bval
);
1072 /* Treat RTI like RTS */
1079 bval
=getaddr(addr
)^0xff;
1080 wval
=(unsigned short)a
+bval
+((p
&FLAG_C
)?1:0);
1081 setflags(FLAG_C
, wval
&0x100);
1082 a
=(unsigned char)wval
;
1083 setflags(FLAG_Z
, !a
);
1084 setflags(FLAG_N
, a
>127);
1085 setflags(FLAG_V
, (!!(p
&FLAG_C
)) ^ (!!(p
&FLAG_N
)));
1107 setflags(FLAG_Z
, !x
);
1108 setflags(FLAG_N
, x
&0x80);
1112 setflags(FLAG_Z
, !y
);
1113 setflags(FLAG_N
, y
&0x80);
1117 setflags(FLAG_Z
, !x
);
1118 setflags(FLAG_N
, x
&0x80);
1122 setflags(FLAG_Z
, !a
);
1123 setflags(FLAG_N
, a
&0x80);
1130 setflags(FLAG_Z
, !a
);
1131 setflags(FLAG_N
, a
&0x80);
1136 void cpuJSR(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
1137 void cpuJSR(unsigned short npc
, unsigned char na
)
1153 void c64Init(int nSampleRate
) ICODE_ATTR
;
1154 void c64Init(int nSampleRate
)
1156 synth_init(nSampleRate
);
1157 memset(memory
, 0, sizeof(memory
));
1164 unsigned short LoadSIDFromMemory(void *pSidData
, unsigned short *load_addr
,
1165 unsigned short *init_addr
, unsigned short *play_addr
, unsigned char *subsongs
, unsigned char *startsong
, unsigned char *speed
, unsigned short size
) ICODE_ATTR
;
1166 unsigned short LoadSIDFromMemory(void *pSidData
, unsigned short *load_addr
,
1167 unsigned short *init_addr
, unsigned short *play_addr
, unsigned char *subsongs
, unsigned char *startsong
, unsigned char *speed
, unsigned short size
)
1169 unsigned char *pData
;
1170 unsigned char data_file_offset
;
1172 pData
= (unsigned char*)pSidData
;
1173 data_file_offset
= pData
[7];
1175 *load_addr
= pData
[8]<<8;
1176 *load_addr
|= pData
[9];
1178 *init_addr
= pData
[10]<<8;
1179 *init_addr
|= pData
[11];
1181 *play_addr
= pData
[12]<<8;
1182 *play_addr
|= pData
[13];
1184 *subsongs
= pData
[0xf]-1;
1185 *startsong
= pData
[0x11]-1;
1187 *load_addr
= pData
[data_file_offset
];
1188 *load_addr
|= pData
[data_file_offset
+1]<<8;
1190 *speed
= pData
[0x15];
1192 memset(memory
, 0, sizeof(memory
));
1193 memcpy(&memory
[*load_addr
], &pData
[data_file_offset
+2], size
-(data_file_offset
+2));
1195 if (*play_addr
== 0)
1197 cpuJSR(*init_addr
, 0);
1198 *play_addr
= (memory
[0x0315]<<8)+memory
[0x0314];
1205 enum codec_status
codec_main(void)
1207 size_t n
, bytesfree
;
1209 unsigned int filesize
;
1211 unsigned short load_addr
, init_addr
, play_addr
;
1212 unsigned char subSongsMax
, subSong
, song_speed
;
1214 int nSamplesRendered
= 0;
1215 int nSamplesPerCall
= 882; /* This is PAL SID single speed (44100/50Hz) */
1216 int nSamplesToRender
= 0;
1218 /* Generic codec initialisation */
1219 ci
->configure(CODEC_SET_FILEBUF_WATERMARK
, 1024*512);
1220 ci
->configure(CODEC_SET_FILEBUF_CHUNKSIZE
, 1024*256);
1227 while (!*ci
->taginfo_ready
)
1230 codec_set_replaygain(ci
->id3
);
1234 bytesfree
=sizeof(sidfile
);
1235 while ((n
= ci
->read_filebuf(p
, bytesfree
)) > 0) {
1239 filesize
= p
-sidfile
;
1245 LoadSIDFromMemory(sidfile
, &load_addr
, &init_addr
, &play_addr
, &subSongsMax
, &subSong
, &song_speed
, filesize
);
1246 sidPoke(24, 15); /* Turn on full volume */
1247 cpuJSR(init_addr
, subSong
); /* Start the song initialize */
1250 /* Make use of 44.1khz */
1251 ci
->configure(DSP_SWITCH_FREQUENCY
, 44100);
1252 /* Sample depth is 28 bit host endian */
1253 ci
->configure(DSP_SET_SAMPLE_DEPTH
, 28);
1255 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
1258 /* Set the elapsed time to the current subsong (in seconds) */
1259 ci
->set_elapsed(subSong
*1000);
1261 /* The main decoder loop */
1264 if (ci
->stop_codec
|| ci
->new_track
)
1267 if (ci
->seek_time
) {
1268 /* New time is ready in ci->seek_time */
1270 /* Start playing from scratch */
1272 LoadSIDFromMemory(sidfile
, &load_addr
, &init_addr
, &play_addr
, &subSongsMax
, &subSong
, &song_speed
, filesize
);
1273 sidPoke(24, 15); /* Turn on full volume */
1274 subSong
= ci
->seek_time
/ 1000; /* Now use the current seek time in seconds as subsong */
1275 cpuJSR(init_addr
, subSong
); /* Start the song initialize */
1276 nSamplesToRender
= 0; /* Start the rendering from scratch */
1278 ci
->seek_complete();
1280 /* Set the elapsed time to the current subsong (in seconds) */
1281 ci
->set_elapsed(subSong
*1000);
1284 nSamplesRendered
= 0;
1285 while (nSamplesRendered
< CHUNK_SIZE
)
1287 if (nSamplesToRender
== 0)
1289 cpuJSR(play_addr
, 0);
1291 /* Find out if cia timing is used and how many samples
1292 have to be calculated for each cpujsr */
1293 int nRefreshCIA
= (int)(20000*(memory
[0xdc04]|(memory
[0xdc05]<<8))/0x4c00);
1294 if ((nRefreshCIA
==0) || (song_speed
== 0))
1295 nRefreshCIA
= 20000;
1296 nSamplesPerCall
= mixing_frequency
*nRefreshCIA
/1000000;
1298 nSamplesToRender
= nSamplesPerCall
;
1300 if (nSamplesRendered
+ nSamplesToRender
> CHUNK_SIZE
)
1302 synth_render(samples
+nSamplesRendered
, CHUNK_SIZE
-nSamplesRendered
);
1303 nSamplesToRender
-= CHUNK_SIZE
-nSamplesRendered
;
1304 nSamplesRendered
= CHUNK_SIZE
;
1308 synth_render(samples
+nSamplesRendered
, nSamplesToRender
);
1309 nSamplesRendered
+= nSamplesToRender
;
1310 nSamplesToRender
= 0;
1314 ci
->pcmbuf_insert(samples
, NULL
, CHUNK_SIZE
);
1317 if (ci
->request_next_track())