blob: 0edbabe0b6cf1cf0c01719ed24c50589d4172d11 [file] [log] [blame]
Dave Chapman752faa42006-07-18 18:33:12 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * SID Codec for rockbox based on the TinySID engine
11 *
12 * Written by Tammo Hinrichs (kb) and Rainer Sinsch in 1998-1999
13 * Ported to rockbox on 14 April 2006
14 *
15 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000016 * 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.
Dave Chapman752faa42006-07-18 18:33:12 +000020 *
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied.
23 *
24 ****************************************************************************/
25
26 /*****************************
27 * kb explicitly points out that this emulation sounds crappy, though
28 * we decided to put it open source so everyone can enjoy sidmusic
29 * on rockbox
30 *
31 *****************************/
32
33 /*********************
34 * v1.1
35 * Added 16-04-2006: Rainer Sinsch
36 * Removed all time critical floating point operations and
37 * replaced them with quick & dirty integer calculations
38 *
39 * Added 17-04-2006: Rainer Sinsch
40 * Improved quick & dirty integer calculations for the resonant filter
41 * Improved audio quality by 4 bits
42 *
43 * v1.2
44 * Added 17-04-2006: Dave Chapman
45 * Improved file loading
46 *
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
52 *
53 * v1.2.1
54 * Added 04-05-2006: Rainer Sinsch
55 * Implemented Marco Alanens suggestion for subsong selection:
56 * Select the subsong by seeking: Each second represents a subsong
57 *
58 **************************/
59
60#define USE_FILTER
61
62#include "debug.h"
63#include "codeclib.h"
64#include <inttypes.h>
65
66CODEC_HEADER
67
68#define CHUNK_SIZE (1024*2)
69
Dave Chapman752faa42006-07-18 18:33:12 +000070/* This codec supports SID Files:
71 *
72 */
73
Dave Chapman752faa42006-07-18 18:33:12 +000074static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
75
76/* Static buffer for the plain SID-File */
77static unsigned char sidfile[0x10000];
78
79void sidPoke(int reg, unsigned char val) ICODE_ATTR;
80
81#define FLAG_N 128
82#define FLAG_V 64
83#define FLAG_B 16
84#define FLAG_D 8
85#define FLAG_I 4
86#define FLAG_Z 2
87#define FLAG_C 1
88
89#define imp 0
90#define imm 1
91#define _abs 2
92#define absx 3
93#define absy 4
94#define zp 6
95#define zpx 7
96#define zpy 8
97#define ind 9
98#define indx 10
99#define indy 11
100#define acc 12
101#define rel 13
102
103enum {
Thomas Martitz6eaab4d2010-09-01 21:29:34 +0000104 adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, _brk, bvc, bvs, clc,
Dave Chapman752faa42006-07-18 18:33:12 +0000105 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,
108 xxx
109};
110
111/* SID register definition */
112struct s6581 {
113 struct sidvoice {
114 unsigned short freq;
115 unsigned short pulse;
116 unsigned char wave;
117 unsigned char ad;
118 unsigned char sr;
119 } v[3];
120 unsigned char ffreqlo;
121 unsigned char ffreqhi;
122 unsigned char res_ftv;
123 unsigned char ftp_vol;
124};
125
126/* internal oscillator def */
127struct sidosc {
128 unsigned long freq;
129 unsigned long pulse;
130 unsigned char wave;
131 unsigned char filter;
132 unsigned long attack;
133 unsigned long decay;
134 unsigned long sustain;
135 unsigned long release;
136 unsigned long counter;
137 signed long envval;
138 unsigned char envphase;
139 unsigned long noisepos;
140 unsigned long noiseval;
141 unsigned char noiseout;
142};
143
144/* internal filter def */
145struct sidflt {
146 int freq;
147 unsigned char l_ena;
148 unsigned char b_ena;
149 unsigned char h_ena;
150 unsigned char v3ena;
151 int vol;
152 int rez;
153 int h;
154 int b;
155 int l;
156};
157
158/* ------------------------ pseudo-constants (depending on mixing freq) */
159int mixing_frequency IDATA_ATTR;
160unsigned long freqmul IDATA_ATTR;
161int filtmul IDATA_ATTR;
162unsigned long attacks [16] IDATA_ATTR;
163unsigned long releases[16] IDATA_ATTR;
164
165/* ------------------------------------------------------------ globals */
166struct s6581 sid IDATA_ATTR;
167struct sidosc osc[3] IDATA_ATTR;
168struct sidflt filter IDATA_ATTR;
169
170/* ------------------------------------------------------ C64 Emu Stuff */
171unsigned char bval IDATA_ATTR;
172unsigned short wval IDATA_ATTR;
173/* -------------------------------------------------- Register & memory */
174unsigned char a,x,y,s,p IDATA_ATTR;
175unsigned short pc IDATA_ATTR;
176
177unsigned char memory[65536];
178
179/* ----------------------------------------- Variables for sample stuff */
180static int sample_active IDATA_ATTR;
181static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000182static int fracPos IDATA_ATTR; /* Fractal position of sample */
Dave Chapman752faa42006-07-18 18:33:12 +0000183static int sample_period IDATA_ATTR;
184static int sample_repeats IDATA_ATTR;
185static int sample_order IDATA_ATTR;
186static int sample_nibble IDATA_ATTR;
187
188static int internal_period, internal_order, internal_start, internal_end,
189 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
190
191/* ---------------------------------------------------------- constants */
192static const float attackTimes[16] ICONST_ATTR =
193{
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
198};
199static const float decayReleaseTimes[16] ICONST_ATTR =
200{
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
204};
205
206static const int opcodes[256] ICONST_ATTR = {
Thomas Martitz6eaab4d2010-09-01 21:29:34 +0000207 _brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
Dave Chapman752faa42006-07-18 18:33:12 +0000208 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
223};
224
225
226static 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
243};
244
245/* Routines for quick & dirty float calculation */
246
247static inline int quickfloat_ConvertFromInt(int i)
248{
249 return (i<<16);
250}
251static inline int quickfloat_ConvertFromFloat(float f)
252{
253 return (int)(f*(1<<16));
254}
255static inline int quickfloat_Multiply(int a, int b)
256{
257 return (a>>8)*(b>>8);
258}
259static inline int quickfloat_ConvertToInt(int i)
260{
261 return (i>>16);
262}
263
264/* Get the bit from an unsigned long at a specified position */
265static inline unsigned char get_bit(unsigned long val, unsigned char b)
266{
267 return (unsigned char) ((val >> b) & 1);
268}
269
270
271static inline int GenerateDigi(int sIn)
272{
273 static int last_sample = 0;
274 static int sample = 0;
275
276 if (!sample_active) return(sIn);
277
278 if ((sample_position < sample_end) && (sample_position >= sample_start))
279 {
280 sIn += sample;
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000281
Dave Chapman752faa42006-07-18 18:33:12 +0000282 fracPos += 985248/sample_period;
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000283
Dave Chapman752faa42006-07-18 18:33:12 +0000284 if (fracPos > mixing_frequency)
285 {
286 fracPos%=mixing_frequency;
287
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000288 last_sample = sample;
289
290 // N�hstes Samples holen
Dave Chapman752faa42006-07-18 18:33:12 +0000291 if (sample_order == 0) {
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000292 sample_nibble++; // Nähstes Sample-Nibble
Dave Chapman752faa42006-07-18 18:33:12 +0000293 if (sample_nibble==2) {
294 sample_nibble = 0;
295 sample_position++;
296 }
297 }
298 else {
299 sample_nibble--;
300 if (sample_nibble < 0) {
301 sample_nibble=1;
302 sample_position++;
303 }
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000304 }
Dave Chapman752faa42006-07-18 18:33:12 +0000305 if (sample_repeats)
306 {
307 if (sample_position > sample_end)
308 {
309 sample_repeats--;
310 sample_position = sample_repeat_start;
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000311 }
Dave Chapman752faa42006-07-18 18:33:12 +0000312 else sample_active = 0;
313 }
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000314
Dave Chapman752faa42006-07-18 18:33:12 +0000315 sample = memory[sample_position&0xffff];
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000316 if (sample_nibble==1) // Hi-Nibble holen?
Dave Chapman752faa42006-07-18 18:33:12 +0000317 sample = (sample & 0xf0)>>4;
318 else sample = sample & 0x0f;
319
320 sample -= 7;
Andree Buschmann4d5e8822010-02-07 18:38:47 +0000321 sample <<= 10;
Dave Chapman752faa42006-07-18 18:33:12 +0000322 }
323 }
324
325 return (sIn);
326}
327
328/* ------------------------------------------------------------- synthesis
329 initialize SID and frequency dependant values */
330void synth_init(unsigned long mixfrq) ICODE_ATTR;
331void synth_init(unsigned long mixfrq)
332{
333 int i;
334 mixing_frequency = mixfrq;
335 fracPos = 0;
336 freqmul = 15872000 / mixfrq;
337 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
338 for (i=0;i<16;i++) {
339 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
340 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
341 }
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;
348}
349
350/* render a buffer of n samples with the actual register contents */
351void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
352void synth_render (int32_t *buffer, unsigned long len)
353{
354 unsigned long bp;
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) */
358 unsigned char v;
359 for (v=0;v<3;v++) {
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;
368 }
369
370#ifdef USE_FILTER
371 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
372
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);
386
387 /* We precalculate part of the quick float operation, saves time in loop later */
388 filter.rez>>=8;
389#endif
390
391
392 /* now render the buffer */
393 for (bp=0;bp<len;bp++) {
394#ifdef USE_FILTER
395 int outo=0;
396#endif
397 int outf=0;
398 /* step 2 : generate the two output signals (for filtered and non-
399 filtered) from the osc/eg sections */
400 for (v=0;v<3;v++) {
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) {
405 osc[v].counter = 0;
406 osc[v].noisepos = 0;
407 osc[v].noiseval = 0xffffff;
408 }
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)
417 triout^=0xff;
418 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
419 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
420
421 /* generate noise waveform exactly as the SID does. */
422 if (osc[v].noisepos!=(osc[v].counter>>23))
423 {
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);
435 }
436 unsigned char nseout = osc[v].noiseout;
437
438 /* modulate triangle wave if ringmod bit set */
439 if (osc[v].wave & 0x04)
440 if (osc[refosc].counter < 0x8000000)
441 triout ^= 0xff;
442
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. */
447
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;
453
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)
459 {
460 osc[v].envval = 0xFFFFFF;
461 osc[v].envphase = 1;
462 }
463 break;
464 }
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))
468 {
469 osc[v].envval = osc[v].sustain<<16;
470 osc[v].envphase = 2;
471 }
472 break;
473 }
474 case 2 : { /* Phase 2 : Sustain */
475 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
476 {
477 osc[v].envphase = 1;
478 }
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 :) */
482 break;
483 }
484 case 3 : { /* Phase 3 : Release */
485 osc[v].envval-=osc[v].release;
486 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
487
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 :) */
492 break;
493 }
494 }
495
496#ifdef USE_FILTER
497
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 */
500
501 if (v<2 || filter.v3ena)
502 {
503 if (osc[v].filter)
504 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
505 else
506 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
507 }
508#endif
509#ifndef USE_FILTER
510 /* Don't use filters, just mix all voices together */
511 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
512#endif
513 }
514
515
516#ifdef USE_FILTER
517 /* step 3
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
521 * FIRs ...
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
525 * emulator.
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 :) */
528
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);
532
533 outf = 0;
534
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);
538
539 int final_sample = (filter.vol*(outo+outf));
540 *(buffer+bp)= GenerateDigi(final_sample)<<13;
541#endif
542#ifndef USE_FILTER
543 *(buffer+bp) = GenerateDigi(outf)<<3;
544#endif
545 }
546}
547
548
549
550/*
551* C64 Mem Routines
552*/
553static inline unsigned char getmem(unsigned short addr)
554{
555 return memory[addr];
556}
557
558static inline void setmem(unsigned short addr, unsigned char value)
559{
560 if ((addr&0xfc00)==0xd400)
561 {
562 sidPoke(addr&0x1f,value);
563 /* New SID-Register */
564 if (addr > 0xd418)
565 {
566 switch (addr)
567 {
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;
598 switch (value)
599 {
600 case 0xfd: sample_active = 0; break;
601 case 0xfe:
602 case 0xff: sample_active = 1; break;
603 default: return;
604 }
605 break;
606 }
607 }
608 }
609 else memory[addr]=value;
610}
611
612/*
613* Poke a value into the sid register
614*/
615void sidPoke(int reg, unsigned char val) ICODE_ATTR;
616void sidPoke(int reg, unsigned char val)
617{
618 int voice=0;
619
620 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
621 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
622
623 switch (reg) {
624 case 0: { /* Set frequency: Low byte */
625 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
626 break;
627 }
628 case 1: { /* Set frequency: High byte */
629 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
630 break;
631 }
632 case 2: { /* Set pulse width: Low byte */
633 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
634 break;
635 }
636 case 3: { /* Set pulse width: High byte */
637 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
638 break;
639 }
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
644 */
645 if ((val & 0x01) == 0) osc[voice].envphase=3;
646 else if (osc[voice].envphase==3) osc[voice].envphase=0;
647 break;
648 }
649
650 case 5: { sid.v[voice].ad = val; break;}
651 case 6: { sid.v[voice].sr = val; break;}
652
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;}
657 }
658 return;
659}
660
661static inline unsigned char getaddr(int mode)
662{
663 unsigned short ad,ad2;
664 switch(mode)
665 {
666 case imp:
667 return 0;
668 case imm:
669 return getmem(pc++);
670 case _abs:
671 ad=getmem(pc++);
672 ad|=256*getmem(pc++);
673 return getmem(ad);
674 case absx:
675 ad=getmem(pc++);
676 ad|=256*getmem(pc++);
677 ad2=ad+x;
678 return getmem(ad2);
679 case absy:
680 ad=getmem(pc++);
681 ad|=256*getmem(pc++);
682 ad2=ad+y;
683 return getmem(ad2);
684 case zp:
685 ad=getmem(pc++);
686 return getmem(ad);
687 case zpx:
688 ad=getmem(pc++);
689 ad+=x;
690 return getmem(ad&0xff);
691 case zpy:
692 ad=getmem(pc++);
693 ad+=y;
694 return getmem(ad&0xff);
695 case indx:
696 ad=getmem(pc++);
697 ad+=x;
698 ad2=getmem(ad&0xff);
699 ad++;
700 ad2|=getmem(ad&0xff)<<8;
701 return getmem(ad2);
702 case indy:
703 ad=getmem(pc++);
704 ad2=getmem(ad);
705 ad2|=getmem((ad+1)&0xff)<<8;
706 ad=ad2+y;
707 return getmem(ad);
708 case acc:
709 return a;
710 }
711 return 0;
712}
713
714static inline void setaddr(int mode, unsigned char val)
715{
716 unsigned short ad,ad2;
717 switch(mode)
718 {
719 case _abs:
720 ad=getmem(pc-2);
721 ad|=256*getmem(pc-1);
722 setmem(ad,val);
723 return;
724 case absx:
725 ad=getmem(pc-2);
726 ad|=256*getmem(pc-1);
727 ad2=ad+x;
728 setmem(ad2,val);
729 return;
730 case zp:
731 ad=getmem(pc-1);
732 setmem(ad,val);
733 return;
734 case zpx:
735 ad=getmem(pc-1);
736 ad+=x;
737 setmem(ad&0xff,val);
738 return;
739 case acc:
740 a=val;
741 return;
742 }
743}
744
745
746static inline void putaddr(int mode, unsigned char val)
747{
748 unsigned short ad,ad2;
749 switch(mode)
750 {
751 case _abs:
752 ad=getmem(pc++);
753 ad|=getmem(pc++)<<8;
754 setmem(ad,val);
755 return;
756 case absx:
757 ad=getmem(pc++);
758 ad|=getmem(pc++)<<8;
759 ad2=ad+x;
760 setmem(ad2,val);
761 return;
762 case absy:
763 ad=getmem(pc++);
764 ad|=getmem(pc++)<<8;
765 ad2=ad+y;
766 setmem(ad2,val);
767 return;
768 case zp:
769 ad=getmem(pc++);
770 setmem(ad,val);
771 return;
772 case zpx:
773 ad=getmem(pc++);
774 ad+=x;
775 setmem(ad&0xff,val);
776 return;
777 case zpy:
778 ad=getmem(pc++);
779 ad+=y;
780 setmem(ad&0xff,val);
781 return;
782 case indx:
783 ad=getmem(pc++);
784 ad+=x;
785 ad2=getmem(ad&0xff);
786 ad++;
787 ad2|=getmem(ad&0xff)<<8;
788 setmem(ad2,val);
789 return;
790 case indy:
791 ad=getmem(pc++);
792 ad2=getmem(ad);
793 ad2|=getmem((ad+1)&0xff)<<8;
794 ad=ad2+y;
795 setmem(ad,val);
796 return;
797 case acc:
798 a=val;
799 return;
800 }
801}
802
803
804static inline void setflags(int flag, int cond)
805{
806 if (cond) p|=flag;
807 else p&=~flag;
808}
809
810
811static inline void push(unsigned char val)
812{
813 setmem(0x100+s,val);
814 if (s) s--;
815}
816
817static inline unsigned char pop(void)
818{
819 if (s<0xff) s++;
820 return getmem(0x100+s);
821}
822
823static inline void branch(int flag)
824{
825 signed char dist;
826 dist=(signed char)getaddr(imm);
827 wval=pc+dist;
828 if (flag) pc=wval;
829}
830
831void cpuReset(void) ICODE_ATTR;
832void cpuReset(void)
833{
834 a=x=y=0;
835 p=0;
836 s=255;
837 pc=getaddr(0xfffc);
838}
839
840void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
841void cpuResetTo(unsigned short npc, unsigned char na)
842{
843 a=na;
844 x=0;
845 y=0;
846 p=0;
847 s=255;
848 pc=npc;
849}
850
851static inline void cpuParse(void)
852{
853 unsigned char opc=getmem(pc++);
854 int cmd=opcodes[opc];
855 int addr=modes[opc];
856 int c;
857 switch (cmd)
858 {
859 case adc:
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)));
866 break;
867 case _and:
868 bval=getaddr(addr);
869 a&=bval;
870 setflags(FLAG_Z, !a);
871 setflags(FLAG_N, a&0x80);
872 break;
873 case asl:
874 wval=getaddr(addr);
875 wval<<=1;
876 setaddr(addr,(unsigned char)wval);
877 setflags(FLAG_Z,!wval);
878 setflags(FLAG_N,wval&0x80);
879 setflags(FLAG_C,wval&0x100);
880 break;
881 case bcc:
882 branch(!(p&FLAG_C));
883 break;
884 case bcs:
885 branch(p&FLAG_C);
886 break;
887 case bne:
888 branch(!(p&FLAG_Z));
889 break;
890 case beq:
891 branch(p&FLAG_Z);
892 break;
893 case bpl:
894 branch(!(p&FLAG_N));
895 break;
896 case bmi:
897 branch(p&FLAG_N);
898 break;
899 case bvc:
900 branch(!(p&FLAG_V));
901 break;
902 case bvs:
903 branch(p&FLAG_V);
904 break;
905 case bit:
906 bval=getaddr(addr);
907 setflags(FLAG_Z,!(a&bval));
908 setflags(FLAG_N,bval&0x80);
909 setflags(FLAG_V,bval&0x40);
910 break;
Thomas Martitz6eaab4d2010-09-01 21:29:34 +0000911 case _brk:
Dave Chapman752faa42006-07-18 18:33:12 +0000912 pc=0; /* Just quit the emulation */
913 break;
914 case clc:
915 setflags(FLAG_C,0);
916 break;
917 case cld:
918 setflags(FLAG_D,0);
919 break;
920 case cli:
921 setflags(FLAG_I,0);
922 break;
923 case clv:
924 setflags(FLAG_V,0);
925 break;
926 case cmp:
927 bval=getaddr(addr);
928 wval=(unsigned short)a-bval;
929 setflags(FLAG_Z,!wval);
930 setflags(FLAG_N,wval&0x80);
931 setflags(FLAG_C,a>=bval);
932 break;
933 case cpx:
934 bval=getaddr(addr);
935 wval=(unsigned short)x-bval;
936 setflags(FLAG_Z,!wval);
937 setflags(FLAG_N,wval&0x80);
938 setflags(FLAG_C,x>=bval);
939 break;
940 case cpy:
941 bval=getaddr(addr);
942 wval=(unsigned short)y-bval;
943 setflags(FLAG_Z,!wval);
944 setflags(FLAG_N,wval&0x80);
945 setflags(FLAG_C,y>=bval);
946 break;
947 case dec:
948 bval=getaddr(addr);
949 bval--;
950 setaddr(addr,bval);
951 setflags(FLAG_Z,!bval);
952 setflags(FLAG_N,bval&0x80);
953 break;
954 case dex:
955 x--;
956 setflags(FLAG_Z,!x);
957 setflags(FLAG_N,x&0x80);
958 break;
959 case dey:
960 y--;
961 setflags(FLAG_Z,!y);
962 setflags(FLAG_N,y&0x80);
963 break;
964 case eor:
965 bval=getaddr(addr);
966 a^=bval;
967 setflags(FLAG_Z,!a);
968 setflags(FLAG_N,a&0x80);
969 break;
970 case inc:
971 bval=getaddr(addr);
972 bval++;
973 setaddr(addr,bval);
974 setflags(FLAG_Z,!bval);
975 setflags(FLAG_N,bval&0x80);
976 break;
977 case inx:
978 x++;
979 setflags(FLAG_Z,!x);
980 setflags(FLAG_N,x&0x80);
981 break;
982 case iny:
983 y++;
984 setflags(FLAG_Z,!y);
985 setflags(FLAG_N,y&0x80);
986 break;
987 case jmp:
988 wval=getmem(pc++);
989 wval|=256*getmem(pc++);
990 switch (addr)
991 {
992 case _abs:
993 pc=wval;
994 break;
995 case ind:
996 pc=getmem(wval);
997 pc|=256*getmem(wval+1);
998 break;
999 }
1000 break;
1001 case jsr:
1002 push((pc+1)>>8);
1003 push((pc+1));
1004 wval=getmem(pc++);
1005 wval|=256*getmem(pc++);
1006 pc=wval;
1007 break;
1008 case lda:
1009 a=getaddr(addr);
1010 setflags(FLAG_Z,!a);
1011 setflags(FLAG_N,a&0x80);
1012 break;
1013 case ldx:
1014 x=getaddr(addr);
1015 setflags(FLAG_Z,!x);
1016 setflags(FLAG_N,x&0x80);
1017 break;
1018 case ldy:
1019 y=getaddr(addr);
1020 setflags(FLAG_Z,!y);
1021 setflags(FLAG_N,y&0x80);
1022 break;
1023 case lsr:
1024 bval=getaddr(addr); wval=(unsigned char)bval;
1025 wval>>=1;
1026 setaddr(addr,(unsigned char)wval);
1027 setflags(FLAG_Z,!wval);
1028 setflags(FLAG_N,wval&0x80);
1029 setflags(FLAG_C,bval&1);
1030 break;
1031 case _nop:
1032 break;
1033 case ora:
1034 bval=getaddr(addr);
1035 a|=bval;
1036 setflags(FLAG_Z,!a);
1037 setflags(FLAG_N,a&0x80);
1038 break;
1039 case pha:
1040 push(a);
1041 break;
1042 case php:
1043 push(p);
1044 break;
1045 case pla:
1046 a=pop();
1047 setflags(FLAG_Z,!a);
1048 setflags(FLAG_N,a&0x80);
1049 break;
1050 case plp:
1051 p=pop();
1052 break;
1053 case rol:
1054 bval=getaddr(addr);
1055 c=!!(p&FLAG_C);
1056 setflags(FLAG_C,bval&0x80);
1057 bval<<=1;
1058 bval|=c;
1059 setaddr(addr,bval);
1060 setflags(FLAG_N,bval&0x80);
1061 setflags(FLAG_Z,!bval);
1062 break;
1063 case ror:
1064 bval=getaddr(addr);
1065 c=!!(p&FLAG_C);
1066 setflags(FLAG_C,bval&1);
1067 bval>>=1;
1068 bval|=128*c;
1069 setaddr(addr,bval);
1070 setflags(FLAG_N,bval&0x80);
1071 setflags(FLAG_Z,!bval);
1072 break;
1073 case rti:
1074 /* Treat RTI like RTS */
1075 case rts:
1076 wval=pop();
1077 wval|=pop()<<8;
1078 pc=wval+1;
1079 break;
1080 case sbc:
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)));
1088 break;
1089 case sec:
1090 setflags(FLAG_C,1);
1091 break;
1092 case sed:
1093 setflags(FLAG_D,1);
1094 break;
1095 case sei:
1096 setflags(FLAG_I,1);
1097 break;
1098 case sta:
1099 putaddr(addr,a);
1100 break;
1101 case stx:
1102 putaddr(addr,x);
1103 break;
1104 case sty:
1105 putaddr(addr,y);
1106 break;
1107 case tax:
1108 x=a;
1109 setflags(FLAG_Z, !x);
1110 setflags(FLAG_N, x&0x80);
1111 break;
1112 case tay:
1113 y=a;
1114 setflags(FLAG_Z, !y);
1115 setflags(FLAG_N, y&0x80);
1116 break;
1117 case tsx:
1118 x=s;
1119 setflags(FLAG_Z, !x);
1120 setflags(FLAG_N, x&0x80);
1121 break;
1122 case txa:
1123 a=x;
1124 setflags(FLAG_Z, !a);
1125 setflags(FLAG_N, a&0x80);
1126 break;
1127 case txs:
1128 s=x;
1129 break;
1130 case tya:
1131 a=y;
1132 setflags(FLAG_Z, !a);
1133 setflags(FLAG_N, a&0x80);
1134 break;
1135 }
1136}
1137
1138void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1139void cpuJSR(unsigned short npc, unsigned char na)
1140{
1141 a=na;
1142 x=0;
1143 y=0;
1144 p=0;
1145 s=255;
1146 pc=npc;
1147 push(0);
1148 push(0);
1149
1150 while (pc > 1)
1151 cpuParse();
1152
1153}
1154
1155void c64Init(int nSampleRate) ICODE_ATTR;
1156void c64Init(int nSampleRate)
1157{
1158 synth_init(nSampleRate);
1159 memset(memory, 0, sizeof(memory));
1160
1161 cpuReset();
1162}
1163
1164
1165
1166unsigned 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;
1168unsigned 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)
1170{
1171 unsigned char *pData;
1172 unsigned char data_file_offset;
1173
1174 pData = (unsigned char*)pSidData;
1175 data_file_offset = pData[7];
1176
1177 *load_addr = pData[8]<<8;
1178 *load_addr|= pData[9];
1179
1180 *init_addr = pData[10]<<8;
1181 *init_addr|= pData[11];
1182
1183 *play_addr = pData[12]<<8;
1184 *play_addr|= pData[13];
1185
1186 *subsongs = pData[0xf]-1;
1187 *startsong = pData[0x11]-1;
1188
1189 *load_addr = pData[data_file_offset];
1190 *load_addr|= pData[data_file_offset+1]<<8;
1191
1192 *speed = pData[0x15];
1193
1194 memset(memory, 0, sizeof(memory));
1195 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1196
1197 if (*play_addr == 0)
1198 {
1199 cpuJSR(*init_addr, 0);
1200 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1201 }
1202
1203 return *load_addr;
1204}
1205
Michael Sevakisc537d592011-04-27 03:08:23 +00001206static int nSamplesRendered = 0;
1207static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1208static int nSamplesToRender = 0;
Dave Chapman752faa42006-07-18 18:33:12 +00001209
Michael Sevakisc537d592011-04-27 03:08:23 +00001210/* this is the codec entry point */
1211enum codec_status codec_main(enum codec_entry_call_reason reason)
1212{
1213 if (reason == CODEC_LOAD) {
1214 /* Make use of 44.1khz */
1215 ci->configure(DSP_SWITCH_FREQUENCY, 44100);
1216 /* Sample depth is 28 bit host endian */
1217 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1218 /* Mono output */
1219 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1220 }
1221
1222 return CODEC_OK;
1223}
1224
1225/* this is called for each file to process */
1226enum codec_status codec_run(void)
Dave Chapman752faa42006-07-18 18:33:12 +00001227{
Dave Chapman752faa42006-07-18 18:33:12 +00001228 unsigned int filesize;
Dave Chapman752faa42006-07-18 18:33:12 +00001229 unsigned short load_addr, init_addr, play_addr;
1230 unsigned char subSongsMax, subSong, song_speed;
Michael Sevakisc537d592011-04-27 03:08:23 +00001231 intptr_t param;
Dave Chapman752faa42006-07-18 18:33:12 +00001232
Tomasz Malesinski80da8b12006-11-26 18:31:41 +00001233 if (codec_init()) {
Dave Chapman752faa42006-07-18 18:33:12 +00001234 return CODEC_ERROR;
1235 }
1236
Michael Sevakis9b9e2272007-02-26 17:15:04 +00001237 codec_set_replaygain(ci->id3);
Dave Chapman752faa42006-07-18 18:33:12 +00001238
Brandon Low4bde8982007-10-25 18:58:44 +00001239 /* Load SID file the read_filebuf callback will return the full requested
Michael Sevakisc537d592011-04-27 03:08:23 +00001240 * size if at all possible, so there is no need to loop */
1241 ci->seek_buffer(0);
Brandon Low4bde8982007-10-25 18:58:44 +00001242 filesize = ci->read_filebuf(sidfile, sizeof(sidfile));
Dave Chapman752faa42006-07-18 18:33:12 +00001243
Michael Sevakisc537d592011-04-27 03:08:23 +00001244 if (filesize == 0) {
Dave Chapman752faa42006-07-18 18:33:12 +00001245 return CODEC_ERROR;
Michael Sevakisc537d592011-04-27 03:08:23 +00001246 }
Dave Chapman752faa42006-07-18 18:33:12 +00001247
1248 c64Init(44100);
Brandon Low4bde8982007-10-25 18:58:44 +00001249 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1250 &subSongsMax, &subSong, &song_speed, filesize);
Dave Chapman752faa42006-07-18 18:33:12 +00001251 sidPoke(24, 15); /* Turn on full volume */
1252 cpuJSR(init_addr, subSong); /* Start the song initialize */
1253
1254
Dave Chapman752faa42006-07-18 18:33:12 +00001255 /* Set the elapsed time to the current subsong (in seconds) */
1256 ci->set_elapsed(subSong*1000);
1257
1258 /* The main decoder loop */
1259 while (1) {
Michael Sevakisc537d592011-04-27 03:08:23 +00001260 enum codec_command_action action = ci->get_command(&param);
1261
1262 if (action == CODEC_ACTION_HALT)
Dave Chapman752faa42006-07-18 18:33:12 +00001263 break;
1264
Michael Sevakisc537d592011-04-27 03:08:23 +00001265 if (action == CODEC_ACTION_SEEK_TIME) {
1266 /* New time is ready in param */
Dave Chapman752faa42006-07-18 18:33:12 +00001267
1268 /* Start playing from scratch */
1269 c64Init(44100);
Michael Sevakisc537d592011-04-27 03:08:23 +00001270 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr,
1271 &subSongsMax, &subSong, &song_speed, filesize);
1272 sidPoke(24, 15); /* Turn on full volume */
1273 subSong = param / 1000; /* Now use the current seek time in seconds as subsong */
1274 cpuJSR(init_addr, subSong); /* Start the song initialize */
1275 nSamplesToRender = 0; /* Start the rendering from scratch */
Dave Chapman752faa42006-07-18 18:33:12 +00001276
1277 /* Set the elapsed time to the current subsong (in seconds) */
Michael Sevakisc537d592011-04-27 03:08:23 +00001278 ci->seek_complete();
Dave Chapman752faa42006-07-18 18:33:12 +00001279 ci->set_elapsed(subSong*1000);
1280 }
1281
1282 nSamplesRendered = 0;
1283 while (nSamplesRendered < CHUNK_SIZE)
1284 {
1285 if (nSamplesToRender == 0)
1286 {
1287 cpuJSR(play_addr, 0);
1288
1289 /* Find out if cia timing is used and how many samples
1290 have to be calculated for each cpujsr */
Andree Buschmann4d5e8822010-02-07 18:38:47 +00001291 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
Dave Chapman752faa42006-07-18 18:33:12 +00001292 if ((nRefreshCIA==0) || (song_speed == 0))
1293 nRefreshCIA = 20000;
1294 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1295
1296 nSamplesToRender = nSamplesPerCall;
1297 }
1298 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1299 {
1300 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1301 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1302 nSamplesRendered = CHUNK_SIZE;
1303 }
1304 else
1305 {
1306 synth_render(samples+nSamplesRendered, nSamplesToRender);
1307 nSamplesRendered += nSamplesToRender;
1308 nSamplesToRender = 0;
1309 }
1310 }
1311
Michael Sevakisaba6ca02007-02-07 00:51:50 +00001312 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
Dave Chapman752faa42006-07-18 18:33:12 +00001313 }
1314
Dave Chapman752faa42006-07-18 18:33:12 +00001315 return CODEC_OK;
1316}