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 last_sample
= 0;
274 static int sample
= 0;
276 if (!sample_active
) return(sIn
);
278 if ((sample_position
< sample_end
) && (sample_position
>= sample_start
))
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) {
300 if (sample_nibble
< 0) {
307 if (sample_position
> sample_end
)
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;
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
)
334 mixing_frequency
= mixfrq
;
336 freqmul
= 15872000 / mixfrq
;
337 filtmul
= quickfloat_ConvertFromFloat(21.5332031f
)/mixfrq
;
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
)
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) */
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
;
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 */
392 /* now render the buffer */
393 for (bp
=0;bp
<len
;bp
++) {
398 /* step 2 : generate the two output signals (for filtered and non-
399 filtered) from the osc/eg sections */
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) {
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)
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)
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;
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;
474 case 2 : { /* Phase 2 : Sustain */
475 if ((signed int) osc
[v
].envval
!= (signed int) (osc
[v
].sustain
<<16))
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 :) */
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 :) */
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
)
504 outf
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
506 outo
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
510 /* Don't use filters, just mix all voices together */
511 outf
+=((signed short)(outv
-0x80)) * (osc
[v
].envval
>>4);
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
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
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
);
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;
543 *(buffer
+bp
) = GenerateDigi(outf
)<<3;
553 static inline unsigned char getmem(unsigned short 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 */
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
;
600 case 0xfd: sample_active
= 0; break;
602 case 0xff: sample_active
= 1; 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
)
620 if ((reg
>= 7) && (reg
<=13)) {voice
=1; reg
-=7;}
621 else if ((reg
>= 14) && (reg
<=20)) {voice
=2; reg
-=14;}
624 case 0: { /* Set frequency: Low byte */
625 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff00)+val
;
628 case 1: { /* Set frequency: High byte */
629 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff)+(val
<<8);
632 case 2: { /* Set pulse width: Low byte */
633 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff00)+val
;
636 case 3: { /* Set pulse width: High byte */
637 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff)+(val
<<8);
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;
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;}
661 static inline unsigned char getaddr(int mode
)
663 unsigned short ad
,ad2
;
672 ad
|=256*getmem(pc
++);
676 ad
|=256*getmem(pc
++);
681 ad
|=256*getmem(pc
++);
690 return getmem(ad
&0xff);
694 return getmem(ad
&0xff);
700 ad2
|=getmem(ad
&0xff)<<8;
705 ad2
|=getmem((ad
+1)&0xff)<<8;
714 static inline void setaddr(int mode
, unsigned char val
)
716 unsigned short ad
,ad2
;
721 ad
|=256*getmem(pc
-1);
726 ad
|=256*getmem(pc
-1);
746 static inline void putaddr(int mode
, unsigned char val
)
748 unsigned short ad
,ad2
;
787 ad2
|=getmem(ad
&0xff)<<8;
793 ad2
|=getmem((ad
+1)&0xff)<<8;
804 static inline void setflags(int flag
, int cond
)
811 static inline void push(unsigned char val
)
817 static inline unsigned char pop(void)
820 return getmem(0x100+s
);
823 static inline void branch(int flag
)
826 dist
=(signed char)getaddr(imm
);
831 void cpuReset(void) ICODE_ATTR
;
840 void cpuResetTo(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
841 void cpuResetTo(unsigned short npc
, unsigned char na
)
851 static inline void cpuParse(void)
853 unsigned char opc
=getmem(pc
++);
854 int cmd
=opcodes
[opc
];
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
)));
870 setflags(FLAG_Z
, !a
);
871 setflags(FLAG_N
, a
&0x80);
876 setaddr(addr
,(unsigned char)wval
);
877 setflags(FLAG_Z
,!wval
);
878 setflags(FLAG_N
,wval
&0x80);
879 setflags(FLAG_C
,wval
&0x100);
907 setflags(FLAG_Z
,!(a
&bval
));
908 setflags(FLAG_N
,bval
&0x80);
909 setflags(FLAG_V
,bval
&0x40);
912 pc
=0; /* Just quit the emulation */
928 wval
=(unsigned short)a
-bval
;
929 setflags(FLAG_Z
,!wval
);
930 setflags(FLAG_N
,wval
&0x80);
931 setflags(FLAG_C
,a
>=bval
);
935 wval
=(unsigned short)x
-bval
;
936 setflags(FLAG_Z
,!wval
);
937 setflags(FLAG_N
,wval
&0x80);
938 setflags(FLAG_C
,x
>=bval
);
942 wval
=(unsigned short)y
-bval
;
943 setflags(FLAG_Z
,!wval
);
944 setflags(FLAG_N
,wval
&0x80);
945 setflags(FLAG_C
,y
>=bval
);
951 setflags(FLAG_Z
,!bval
);
952 setflags(FLAG_N
,bval
&0x80);
957 setflags(FLAG_N
,x
&0x80);
962 setflags(FLAG_N
,y
&0x80);
968 setflags(FLAG_N
,a
&0x80);
974 setflags(FLAG_Z
,!bval
);
975 setflags(FLAG_N
,bval
&0x80);
980 setflags(FLAG_N
,x
&0x80);
985 setflags(FLAG_N
,y
&0x80);
989 wval
|=256*getmem(pc
++);
997 pc
|=256*getmem(wval
+1);
1005 wval
|=256*getmem(pc
++);
1010 setflags(FLAG_Z
,!a
);
1011 setflags(FLAG_N
,a
&0x80);
1015 setflags(FLAG_Z
,!x
);
1016 setflags(FLAG_N
,x
&0x80);
1020 setflags(FLAG_Z
,!y
);
1021 setflags(FLAG_N
,y
&0x80);
1024 bval
=getaddr(addr
); wval
=(unsigned char)bval
;
1026 setaddr(addr
,(unsigned char)wval
);
1027 setflags(FLAG_Z
,!wval
);
1028 setflags(FLAG_N
,wval
&0x80);
1029 setflags(FLAG_C
,bval
&1);
1036 setflags(FLAG_Z
,!a
);
1037 setflags(FLAG_N
,a
&0x80);
1047 setflags(FLAG_Z
,!a
);
1048 setflags(FLAG_N
,a
&0x80);
1056 setflags(FLAG_C
,bval
&0x80);
1060 setflags(FLAG_N
,bval
&0x80);
1061 setflags(FLAG_Z
,!bval
);
1066 setflags(FLAG_C
,bval
&1);
1070 setflags(FLAG_N
,bval
&0x80);
1071 setflags(FLAG_Z
,!bval
);
1074 /* Treat RTI like RTS */
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
)));
1109 setflags(FLAG_Z
, !x
);
1110 setflags(FLAG_N
, x
&0x80);
1114 setflags(FLAG_Z
, !y
);
1115 setflags(FLAG_N
, y
&0x80);
1119 setflags(FLAG_Z
, !x
);
1120 setflags(FLAG_N
, x
&0x80);
1124 setflags(FLAG_Z
, !a
);
1125 setflags(FLAG_N
, a
&0x80);
1132 setflags(FLAG_Z
, !a
);
1133 setflags(FLAG_N
, a
&0x80);
1138 void cpuJSR(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
1139 void cpuJSR(unsigned short npc
, unsigned char na
)
1155 void c64Init(int nSampleRate
) ICODE_ATTR
;
1156 void c64Init(int nSampleRate
)
1158 synth_init(nSampleRate
);
1159 memset(memory
, 0, sizeof(memory
));
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];
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;
1223 while (!*ci
->taginfo_ready
&& !ci
->stop_codec
)
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
));
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);
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 */
1256 if (ci
->stop_codec
|| ci
->new_track
)
1259 if (ci
->seek_time
) {
1260 /* New time is ready in ci->seek_time */
1262 /* Start playing from scratch */
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
;
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())