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)
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
;
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 */
114 unsigned short pulse
;
119 unsigned char ffreqlo
;
120 unsigned char ffreqhi
;
121 unsigned char res_ftv
;
122 unsigned char ftp_vol
;
125 /* internal oscillator def */
130 unsigned char filter
;
131 unsigned long attack
;
133 unsigned long sustain
;
134 unsigned long release
;
135 unsigned long counter
;
137 unsigned char envphase
;
138 unsigned long noisepos
;
139 unsigned long noiseval
;
140 unsigned char noiseout
;
143 /* internal filter def */
157 /* ------------------------ pseudo-constants (depending on mixing freq) */
158 int mixing_frequency IDATA_ATTR
;
159 unsigned long freqmul IDATA_ATTR
;
160 int filtmul IDATA_ATTR
;
162 unsigned long attacks
[16] IDATA_ATTR
;
163 unsigned long releases
[16] IDATA_ATTR
;
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 */
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
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)
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
)
270 static inline int quickfloat_ConvertFromFloat(float f
)
272 return (int)(f
*(1<<16));
275 #define quickfloat_ConvertFromFloat(X) (int)(X*(1<<16))
277 static inline int quickfloat_Multiply(int a
, int b
)
279 return (a
>>8)*(b
>>8);
281 static inline int quickfloat_ConvertToInt(int i
)
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
))
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) {
319 if (sample_nibble
< 0) {
326 if (sample_position
> sample_end
)
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;
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
)
355 mixing_frequency
= mixfrq
;
357 freqmul
= 15872000 / mixfrq
;
358 filtmul
= quickfloat_ConvertFromFloat(21.5332031f
)/mixfrq
;
361 attacks
[i
]=(int) (0x1000000 / (attackTimes
[i
]*mixfrq
));
362 releases
[i
]=(int) (0x1000000 / (decayReleaseTimes
[i
]*mixfrq
));
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
)
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) */
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
;
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 */
415 /* now render the buffer */
416 for (bp
=0;bp
<len
;bp
++) {
421 /* step 2 : generate the two output signals (for filtered and non-
422 filtered) from the osc/eg sections */
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) {
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)
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)
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;
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;
497 case 2 : { /* Phase 2 : Sustain */
498 if ((signed int) osc
[v
].envval
!= (signed int) (osc
[v
].sustain
<<16))
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 :) */
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 :) */
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
)
527 outf
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
529 outo
+=(((int)(outv
-0x80))*osc
[v
].envval
)>>22;
533 /* Don't use filters, just mix all voices together */
534 outf
+=((signed short)(outv
-0x80)) * (osc
[v
].envval
>>4);
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
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
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
);
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;
566 *(buffer
+bp
) = GenerateDigi(outf
)<<3;
576 static inline unsigned char getmem(unsigned short 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 */
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
;
623 case 0xfd: sample_active
= 0; break;
625 case 0xff: sample_active
= 1; 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
)
643 if ((reg
>= 7) && (reg
<=13)) {voice
=1; reg
-=7;}
644 else if ((reg
>= 14) && (reg
<=20)) {voice
=2; reg
-=14;}
647 case 0: { /* Set frequency: Low byte */
648 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff00)+val
;
651 case 1: { /* Set frequency: High byte */
652 sid
.v
[voice
].freq
= (sid
.v
[voice
].freq
&0xff)+(val
<<8);
655 case 2: { /* Set pulse width: Low byte */
656 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff00)+val
;
659 case 3: { /* Set pulse width: High byte */
660 sid
.v
[voice
].pulse
= (sid
.v
[voice
].pulse
&0xff)+(val
<<8);
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;
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;}
684 static inline unsigned char getaddr(int mode
)
686 unsigned short ad
,ad2
;
695 ad
|=256*getmem(pc
++);
699 ad
|=256*getmem(pc
++);
704 ad
|=256*getmem(pc
++);
713 return getmem(ad
&0xff);
717 return getmem(ad
&0xff);
723 ad2
|=getmem(ad
&0xff)<<8;
728 ad2
|=getmem((ad
+1)&0xff)<<8;
737 static inline void setaddr(int mode
, unsigned char val
)
739 unsigned short ad
,ad2
;
744 ad
|=256*getmem(pc
-1);
749 ad
|=256*getmem(pc
-1);
769 static inline void putaddr(int mode
, unsigned char val
)
771 unsigned short ad
,ad2
;
810 ad2
|=getmem(ad
&0xff)<<8;
816 ad2
|=getmem((ad
+1)&0xff)<<8;
827 static inline void setflags(int flag
, int cond
)
834 static inline void push(unsigned char val
)
840 static inline unsigned char pop(void)
843 return getmem(0x100+s
);
846 static inline void branch(int flag
)
849 dist
=(signed char)getaddr(imm
);
854 void cpuReset(void) ICODE_ATTR
;
863 void cpuResetTo(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
864 void cpuResetTo(unsigned short npc
, unsigned char na
)
874 static inline void cpuParse(void)
876 unsigned char opc
=getmem(pc
++);
877 int cmd
=opcodes
[opc
];
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
)));
893 setflags(FLAG_Z
, !a
);
894 setflags(FLAG_N
, a
&0x80);
899 setaddr(addr
,(unsigned char)wval
);
900 setflags(FLAG_Z
,!wval
);
901 setflags(FLAG_N
,wval
&0x80);
902 setflags(FLAG_C
,wval
&0x100);
930 setflags(FLAG_Z
,!(a
&bval
));
931 setflags(FLAG_N
,bval
&0x80);
932 setflags(FLAG_V
,bval
&0x40);
935 pc
=0; /* Just quit the emulation */
951 wval
=(unsigned short)a
-bval
;
952 setflags(FLAG_Z
,!wval
);
953 setflags(FLAG_N
,wval
&0x80);
954 setflags(FLAG_C
,a
>=bval
);
958 wval
=(unsigned short)x
-bval
;
959 setflags(FLAG_Z
,!wval
);
960 setflags(FLAG_N
,wval
&0x80);
961 setflags(FLAG_C
,x
>=bval
);
965 wval
=(unsigned short)y
-bval
;
966 setflags(FLAG_Z
,!wval
);
967 setflags(FLAG_N
,wval
&0x80);
968 setflags(FLAG_C
,y
>=bval
);
974 setflags(FLAG_Z
,!bval
);
975 setflags(FLAG_N
,bval
&0x80);
980 setflags(FLAG_N
,x
&0x80);
985 setflags(FLAG_N
,y
&0x80);
991 setflags(FLAG_N
,a
&0x80);
997 setflags(FLAG_Z
,!bval
);
998 setflags(FLAG_N
,bval
&0x80);
1002 setflags(FLAG_Z
,!x
);
1003 setflags(FLAG_N
,x
&0x80);
1007 setflags(FLAG_Z
,!y
);
1008 setflags(FLAG_N
,y
&0x80);
1012 wval
|=256*getmem(pc
++);
1020 pc
|=256*getmem(wval
+1);
1028 wval
|=256*getmem(pc
++);
1033 setflags(FLAG_Z
,!a
);
1034 setflags(FLAG_N
,a
&0x80);
1038 setflags(FLAG_Z
,!x
);
1039 setflags(FLAG_N
,x
&0x80);
1043 setflags(FLAG_Z
,!y
);
1044 setflags(FLAG_N
,y
&0x80);
1047 bval
=getaddr(addr
); wval
=(unsigned char)bval
;
1049 setaddr(addr
,(unsigned char)wval
);
1050 setflags(FLAG_Z
,!wval
);
1051 setflags(FLAG_N
,wval
&0x80);
1052 setflags(FLAG_C
,bval
&1);
1059 setflags(FLAG_Z
,!a
);
1060 setflags(FLAG_N
,a
&0x80);
1070 setflags(FLAG_Z
,!a
);
1071 setflags(FLAG_N
,a
&0x80);
1079 setflags(FLAG_C
,bval
&0x80);
1083 setflags(FLAG_N
,bval
&0x80);
1084 setflags(FLAG_Z
,!bval
);
1089 setflags(FLAG_C
,bval
&1);
1093 setflags(FLAG_N
,bval
&0x80);
1094 setflags(FLAG_Z
,!bval
);
1097 /* Treat RTI like RTS */
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
)));
1132 setflags(FLAG_Z
, !x
);
1133 setflags(FLAG_N
, x
&0x80);
1137 setflags(FLAG_Z
, !y
);
1138 setflags(FLAG_N
, y
&0x80);
1142 setflags(FLAG_Z
, !x
);
1143 setflags(FLAG_N
, x
&0x80);
1147 setflags(FLAG_Z
, !a
);
1148 setflags(FLAG_N
, a
&0x80);
1155 setflags(FLAG_Z
, !a
);
1156 setflags(FLAG_N
, a
&0x80);
1161 void cpuJSR(unsigned short npc
, unsigned char na
) ICODE_ATTR
;
1162 void cpuJSR(unsigned short npc
, unsigned char na
)
1178 void c64Init(int nSampleRate
) ICODE_ATTR
;
1179 void c64Init(int nSampleRate
)
1181 synth_init(nSampleRate
);
1182 memset(memory
, 0, sizeof(memory
));
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];
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);
1242 ci
->configure(DSP_SET_STEREO_MODE
, STEREO_MONO
);
1248 /* this is called for each file to process */
1249 enum codec_status
codec_run(void)
1252 unsigned short load_addr
, init_addr
, play_addr
;
1253 unsigned char subSongsMax
, subSong
, song_speed
;
1254 unsigned char *sidfile
= NULL
;
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 */
1266 sidfile
= ci
->request_buffer(&filesize
, SID_BUFFER_SIZE
);
1268 if (filesize
== 0) {
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 */
1284 enum codec_command_action action
= ci
->get_command(¶m
);
1286 if (action
== CODEC_ACTION_HALT
)
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
;
1330 synth_render(samples
+nSamplesRendered
, nSamplesToRender
);
1331 nSamplesRendered
+= nSamplesToRender
;
1332 nSamplesToRender
= 0;
1336 ci
->pcmbuf_insert(samples
, NULL
, CHUNK_SIZE
);