summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/sid.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/sid.c')
-rw-r--r--lib/rbcodec/codecs/sid.c1340
1 files changed, 1340 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/sid.c b/lib/rbcodec/codecs/sid.c
new file mode 100644
index 0000000000..9b19a20ba7
--- /dev/null
+++ b/lib/rbcodec/codecs/sid.c
@@ -0,0 +1,1340 @@
1/***************************************************************************
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 *
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.
20 *
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#define SID_BUFFER_SIZE 0x10000
70#define SAMPLE_RATE 44100
71
72/* This codec supports SID Files:
73 *
74 */
75
76static int32_t samples[CHUNK_SIZE] IBSS_ATTR; /* The sample buffer */
77
78void sidPoke(int reg, unsigned char val) ICODE_ATTR;
79
80#define FLAG_N 128
81#define FLAG_V 64
82#define FLAG_B 16
83#define FLAG_D 8
84#define FLAG_I 4
85#define FLAG_Z 2
86#define FLAG_C 1
87
88#define imp 0
89#define imm 1
90#define _abs 2
91#define absx 3
92#define absy 4
93#define zp 6
94#define zpx 7
95#define zpy 8
96#define ind 9
97#define indx 10
98#define indy 11
99#define acc 12
100#define rel 13
101
102enum {
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,
107 xxx
108};
109
110/* SID register definition */
111struct s6581 {
112 struct sidvoice {
113 unsigned short freq;
114 unsigned short pulse;
115 unsigned char wave;
116 unsigned char ad;
117 unsigned char sr;
118 } v[3];
119 unsigned char ffreqlo;
120 unsigned char ffreqhi;
121 unsigned char res_ftv;
122 unsigned char ftp_vol;
123};
124
125/* internal oscillator def */
126struct sidosc {
127 unsigned long freq;
128 unsigned long pulse;
129 unsigned char wave;
130 unsigned char filter;
131 unsigned long attack;
132 unsigned long decay;
133 unsigned long sustain;
134 unsigned long release;
135 unsigned long counter;
136 signed long envval;
137 unsigned char envphase;
138 unsigned long noisepos;
139 unsigned long noiseval;
140 unsigned char noiseout;
141};
142
143/* internal filter def */
144struct sidflt {
145 int freq;
146 unsigned char l_ena;
147 unsigned char b_ena;
148 unsigned char h_ena;
149 unsigned char v3ena;
150 int vol;
151 int rez;
152 int h;
153 int b;
154 int l;
155};
156
157/* ------------------------ pseudo-constants (depending on mixing freq) */
158int mixing_frequency IDATA_ATTR;
159unsigned long freqmul IDATA_ATTR;
160int filtmul IDATA_ATTR;
161#ifndef ROCKBOX
162unsigned long attacks [16] IDATA_ATTR;
163unsigned long releases[16] IDATA_ATTR;
164#endif
165
166/* ------------------------------------------------------------ globals */
167struct s6581 sid IDATA_ATTR;
168struct sidosc osc[3] IDATA_ATTR;
169struct sidflt filter IDATA_ATTR;
170
171/* ------------------------------------------------------ C64 Emu Stuff */
172unsigned char bval IDATA_ATTR;
173unsigned short wval IDATA_ATTR;
174/* -------------------------------------------------- Register & memory */
175unsigned char a,x,y,s,p IDATA_ATTR;
176unsigned short pc IDATA_ATTR;
177
178unsigned char memory[65536];
179
180/* ----------------------------------------- Variables for sample stuff */
181static int sample_active IDATA_ATTR;
182static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
183static int fracPos IDATA_ATTR; /* Fractal position of sample */
184static int sample_period IDATA_ATTR;
185static int sample_repeats IDATA_ATTR;
186static int sample_order IDATA_ATTR;
187static int sample_nibble IDATA_ATTR;
188
189static int internal_period, internal_order, internal_start, internal_end,
190 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
191
192/* ---------------------------------------------------------- constants */
193#ifndef ROCKBOX
194static const float attackTimes[16] ICONST_ATTR =
195{
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
200};
201static const float decayReleaseTimes[16] ICONST_ATTR =
202{
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
206};
207#else
208#define DIV(X) ((int)(0x1000000 / (X * SAMPLE_RATE)))
209static const unsigned long attacks[16] ICONST_ATTR =
210{
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)
215};
216static const unsigned long releases[16] ICONST_ATTR =
217{
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)
222};
223#endif
224static 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
241};
242
243
244static 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
261};
262
263/* Routines for quick & dirty float calculation */
264
265static inline int quickfloat_ConvertFromInt(int i)
266{
267 return (i<<16);
268}
269#ifndef ROCKBOX
270static inline int quickfloat_ConvertFromFloat(float f)
271{
272 return (int)(f*(1<<16));
273}
274#else
275#define quickfloat_ConvertFromFloat(X) (int)(X*(1<<16))
276#endif
277static inline int quickfloat_Multiply(int a, int b)
278{
279 return (a>>8)*(b>>8);
280}
281static inline int quickfloat_ConvertToInt(int i)
282{
283 return (i>>16);
284}
285
286/* Get the bit from an unsigned long at a specified position */
287static inline unsigned char get_bit(unsigned long val, unsigned char b)
288{
289 return (unsigned char) ((val >> b) & 1);
290}
291
292
293static inline int GenerateDigi(int sIn)
294{
295 static int sample = 0;
296
297 if (!sample_active) return(sIn);
298
299 if ((sample_position < sample_end) && (sample_position >= sample_start))
300 {
301 sIn += sample;
302
303 fracPos += 985248/sample_period;
304
305 if (fracPos > mixing_frequency)
306 {
307 fracPos%=mixing_frequency;
308
309 // N�hstes Samples holen
310 if (sample_order == 0) {
311 sample_nibble++; // Nähstes Sample-Nibble
312 if (sample_nibble==2) {
313 sample_nibble = 0;
314 sample_position++;
315 }
316 }
317 else {
318 sample_nibble--;
319 if (sample_nibble < 0) {
320 sample_nibble=1;
321 sample_position++;
322 }
323 }
324 if (sample_repeats)
325 {
326 if (sample_position > sample_end)
327 {
328 sample_repeats--;
329 sample_position = sample_repeat_start;
330 }
331 else sample_active = 0;
332 }
333
334 sample = memory[sample_position&0xffff];
335 if (sample_nibble==1) // Hi-Nibble holen?
336 sample = (sample & 0xf0)>>4;
337 else sample = sample & 0x0f;
338
339 sample -= 7;
340 sample <<= 10;
341 }
342 }
343
344 return (sIn);
345}
346
347/* ------------------------------------------------------------- synthesis
348 initialize SID and frequency dependant values */
349void synth_init(unsigned long mixfrq) ICODE_ATTR;
350void synth_init(unsigned long mixfrq)
351{
352#ifndef ROCKBOX
353 int i;
354#endif
355 mixing_frequency = mixfrq;
356 fracPos = 0;
357 freqmul = 15872000 / mixfrq;
358 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
359#ifndef ROCKBOX
360 for (i=0;i<16;i++) {
361 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
362 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
363 }
364#endif
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;
371}
372
373/* render a buffer of n samples with the actual register contents */
374void synth_render (int32_t *buffer, unsigned long len) ICODE_ATTR;
375void synth_render (int32_t *buffer, unsigned long len)
376{
377 unsigned long bp;
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) */
381 unsigned char v;
382 for (v=0;v<3;v++) {
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;
391 }
392
393#ifdef USE_FILTER
394 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
395
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);
409
410 /* We precalculate part of the quick float operation, saves time in loop later */
411 filter.rez>>=8;
412#endif
413
414
415 /* now render the buffer */
416 for (bp=0;bp<len;bp++) {
417#ifdef USE_FILTER
418 int outo=0;
419#endif
420 int outf=0;
421 /* step 2 : generate the two output signals (for filtered and non-
422 filtered) from the osc/eg sections */
423 for (v=0;v<3;v++) {
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) {
428 osc[v].counter = 0;
429 osc[v].noisepos = 0;
430 osc[v].noiseval = 0xffffff;
431 }
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)
440 triout^=0xff;
441 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
442 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
443
444 /* generate noise waveform exactly as the SID does. */
445 if (osc[v].noisepos!=(osc[v].counter>>23))
446 {
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);
458 }
459 unsigned char nseout = osc[v].noiseout;
460
461 /* modulate triangle wave if ringmod bit set */
462 if (osc[v].wave & 0x04)
463 if (osc[refosc].counter < 0x8000000)
464 triout ^= 0xff;
465
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. */
470
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;
476
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)
482 {
483 osc[v].envval = 0xFFFFFF;
484 osc[v].envphase = 1;
485 }
486 break;
487 }
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))
491 {
492 osc[v].envval = osc[v].sustain<<16;
493 osc[v].envphase = 2;
494 }
495 break;
496 }
497 case 2 : { /* Phase 2 : Sustain */
498 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
499 {
500 osc[v].envphase = 1;
501 }
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 :) */
505 break;
506 }
507 case 3 : { /* Phase 3 : Release */
508 osc[v].envval-=osc[v].release;
509 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
510
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 :) */
515 break;
516 }
517 }
518
519#ifdef USE_FILTER
520
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 */
523
524 if (v<2 || filter.v3ena)
525 {
526 if (osc[v].filter)
527 outf+=(((int)(outv-0x80))*osc[v].envval)>>22;
528 else
529 outo+=(((int)(outv-0x80))*osc[v].envval)>>22;
530 }
531#endif
532#ifndef USE_FILTER
533 /* Don't use filters, just mix all voices together */
534 outf+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
535#endif
536 }
537
538
539#ifdef USE_FILTER
540 /* step 3
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
544 * FIRs ...
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
548 * emulator.
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 :) */
551
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);
555
556 outf = 0;
557
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);
561
562 int final_sample = (filter.vol*(outo+outf));
563 *(buffer+bp)= GenerateDigi(final_sample)<<13;
564#endif
565#ifndef USE_FILTER
566 *(buffer+bp) = GenerateDigi(outf)<<3;
567#endif
568 }
569}
570
571
572
573/*
574* C64 Mem Routines
575*/
576static inline unsigned char getmem(unsigned short addr)
577{
578 return memory[addr];
579}
580
581static inline void setmem(unsigned short addr, unsigned char value)
582{
583 if ((addr&0xfc00)==0xd400)
584 {
585 sidPoke(addr&0x1f,value);
586 /* New SID-Register */
587 if (addr > 0xd418)
588 {
589 switch (addr)
590 {
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;
621 switch (value)
622 {
623 case 0xfd: sample_active = 0; break;
624 case 0xfe:
625 case 0xff: sample_active = 1; break;
626 default: return;
627 }
628 break;
629 }
630 }
631 }
632 else memory[addr]=value;
633}
634
635/*
636* Poke a value into the sid register
637*/
638void sidPoke(int reg, unsigned char val) ICODE_ATTR;
639void sidPoke(int reg, unsigned char val)
640{
641 int voice=0;
642
643 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
644 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
645
646 switch (reg) {
647 case 0: { /* Set frequency: Low byte */
648 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
649 break;
650 }
651 case 1: { /* Set frequency: High byte */
652 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
653 break;
654 }
655 case 2: { /* Set pulse width: Low byte */
656 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
657 break;
658 }
659 case 3: { /* Set pulse width: High byte */
660 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
661 break;
662 }
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
667 */
668 if ((val & 0x01) == 0) osc[voice].envphase=3;
669 else if (osc[voice].envphase==3) osc[voice].envphase=0;
670 break;
671 }
672
673 case 5: { sid.v[voice].ad = val; break;}
674 case 6: { sid.v[voice].sr = val; break;}
675
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;}
680 }
681 return;
682}
683
684static inline unsigned char getaddr(int mode)
685{
686 unsigned short ad,ad2;
687 switch(mode)
688 {
689 case imp:
690 return 0;
691 case imm:
692 return getmem(pc++);
693 case _abs:
694 ad=getmem(pc++);
695 ad|=256*getmem(pc++);
696 return getmem(ad);
697 case absx:
698 ad=getmem(pc++);
699 ad|=256*getmem(pc++);
700 ad2=ad+x;
701 return getmem(ad2);
702 case absy:
703 ad=getmem(pc++);
704 ad|=256*getmem(pc++);
705 ad2=ad+y;
706 return getmem(ad2);
707 case zp:
708 ad=getmem(pc++);
709 return getmem(ad);
710 case zpx:
711 ad=getmem(pc++);
712 ad+=x;
713 return getmem(ad&0xff);
714 case zpy:
715 ad=getmem(pc++);
716 ad+=y;
717 return getmem(ad&0xff);
718 case indx:
719 ad=getmem(pc++);
720 ad+=x;
721 ad2=getmem(ad&0xff);
722 ad++;
723 ad2|=getmem(ad&0xff)<<8;
724 return getmem(ad2);
725 case indy:
726 ad=getmem(pc++);
727 ad2=getmem(ad);
728 ad2|=getmem((ad+1)&0xff)<<8;
729 ad=ad2+y;
730 return getmem(ad);
731 case acc:
732 return a;
733 }
734 return 0;
735}
736
737static inline void setaddr(int mode, unsigned char val)
738{
739 unsigned short ad,ad2;
740 switch(mode)
741 {
742 case _abs:
743 ad=getmem(pc-2);
744 ad|=256*getmem(pc-1);
745 setmem(ad,val);
746 return;
747 case absx:
748 ad=getmem(pc-2);
749 ad|=256*getmem(pc-1);
750 ad2=ad+x;
751 setmem(ad2,val);
752 return;
753 case zp:
754 ad=getmem(pc-1);
755 setmem(ad,val);
756 return;
757 case zpx:
758 ad=getmem(pc-1);
759 ad+=x;
760 setmem(ad&0xff,val);
761 return;
762 case acc:
763 a=val;
764 return;
765 }
766}
767
768
769static inline void putaddr(int mode, unsigned char val)
770{
771 unsigned short ad,ad2;
772 switch(mode)
773 {
774 case _abs:
775 ad=getmem(pc++);
776 ad|=getmem(pc++)<<8;
777 setmem(ad,val);
778 return;
779 case absx:
780 ad=getmem(pc++);
781 ad|=getmem(pc++)<<8;
782 ad2=ad+x;
783 setmem(ad2,val);
784 return;
785 case absy:
786 ad=getmem(pc++);
787 ad|=getmem(pc++)<<8;
788 ad2=ad+y;
789 setmem(ad2,val);
790 return;
791 case zp:
792 ad=getmem(pc++);
793 setmem(ad,val);
794 return;
795 case zpx:
796 ad=getmem(pc++);
797 ad+=x;
798 setmem(ad&0xff,val);
799 return;
800 case zpy:
801 ad=getmem(pc++);
802 ad+=y;
803 setmem(ad&0xff,val);
804 return;
805 case indx:
806 ad=getmem(pc++);
807 ad+=x;
808 ad2=getmem(ad&0xff);
809 ad++;
810 ad2|=getmem(ad&0xff)<<8;
811 setmem(ad2,val);
812 return;
813 case indy:
814 ad=getmem(pc++);
815 ad2=getmem(ad);
816 ad2|=getmem((ad+1)&0xff)<<8;
817 ad=ad2+y;
818 setmem(ad,val);
819 return;
820 case acc:
821 a=val;
822 return;
823 }
824}
825
826
827static inline void setflags(int flag, int cond)
828{
829 if (cond) p|=flag;
830 else p&=~flag;
831}
832
833
834static inline void push(unsigned char val)
835{
836 setmem(0x100+s,val);
837 if (s) s--;
838}
839
840static inline unsigned char pop(void)
841{
842 if (s<0xff) s++;
843 return getmem(0x100+s);
844}
845
846static inline void branch(int flag)
847{
848 signed char dist;
849 dist=(signed char)getaddr(imm);
850 wval=pc+dist;
851 if (flag) pc=wval;
852}
853
854void cpuReset(void) ICODE_ATTR;
855void cpuReset(void)
856{
857 a=x=y=0;
858 p=0;
859 s=255;
860 pc=getaddr(0xfffc);
861}
862
863void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
864void cpuResetTo(unsigned short npc, unsigned char na)
865{
866 a=na;
867 x=0;
868 y=0;
869 p=0;
870 s=255;
871 pc=npc;
872}
873
874static inline void cpuParse(void)
875{
876 unsigned char opc=getmem(pc++);
877 int cmd=opcodes[opc];
878 int addr=modes[opc];
879 int c;
880 switch (cmd)
881 {
882 case adc:
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)));
889 break;
890 case _and:
891 bval=getaddr(addr);
892 a&=bval;
893 setflags(FLAG_Z, !a);
894 setflags(FLAG_N, a&0x80);
895 break;
896 case asl:
897 wval=getaddr(addr);
898 wval<<=1;
899 setaddr(addr,(unsigned char)wval);
900 setflags(FLAG_Z,!wval);
901 setflags(FLAG_N,wval&0x80);
902 setflags(FLAG_C,wval&0x100);
903 break;
904 case bcc:
905 branch(!(p&FLAG_C));
906 break;
907 case bcs:
908 branch(p&FLAG_C);
909 break;
910 case bne:
911 branch(!(p&FLAG_Z));
912 break;
913 case beq:
914 branch(p&FLAG_Z);
915 break;
916 case bpl:
917 branch(!(p&FLAG_N));
918 break;
919 case bmi:
920 branch(p&FLAG_N);
921 break;
922 case bvc:
923 branch(!(p&FLAG_V));
924 break;
925 case bvs:
926 branch(p&FLAG_V);
927 break;
928 case bit:
929 bval=getaddr(addr);
930 setflags(FLAG_Z,!(a&bval));
931 setflags(FLAG_N,bval&0x80);
932 setflags(FLAG_V,bval&0x40);
933 break;
934 case _brk:
935 pc=0; /* Just quit the emulation */
936 break;
937 case clc:
938 setflags(FLAG_C,0);
939 break;
940 case cld:
941 setflags(FLAG_D,0);
942 break;
943 case cli:
944 setflags(FLAG_I,0);
945 break;
946 case clv:
947 setflags(FLAG_V,0);
948 break;
949 case cmp:
950 bval=getaddr(addr);
951 wval=(unsigned short)a-bval;
952 setflags(FLAG_Z,!wval);
953 setflags(FLAG_N,wval&0x80);
954 setflags(FLAG_C,a>=bval);
955 break;
956 case cpx:
957 bval=getaddr(addr);
958 wval=(unsigned short)x-bval;
959 setflags(FLAG_Z,!wval);
960 setflags(FLAG_N,wval&0x80);
961 setflags(FLAG_C,x>=bval);
962 break;
963 case cpy:
964 bval=getaddr(addr);
965 wval=(unsigned short)y-bval;
966 setflags(FLAG_Z,!wval);
967 setflags(FLAG_N,wval&0x80);
968 setflags(FLAG_C,y>=bval);
969 break;
970 case dec:
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 dex:
978 x--;
979 setflags(FLAG_Z,!x);
980 setflags(FLAG_N,x&0x80);
981 break;
982 case dey:
983 y--;
984 setflags(FLAG_Z,!y);
985 setflags(FLAG_N,y&0x80);
986 break;
987 case eor:
988 bval=getaddr(addr);
989 a^=bval;
990 setflags(FLAG_Z,!a);
991 setflags(FLAG_N,a&0x80);
992 break;
993 case inc:
994 bval=getaddr(addr);
995 bval++;
996 setaddr(addr,bval);
997 setflags(FLAG_Z,!bval);
998 setflags(FLAG_N,bval&0x80);
999 break;
1000 case inx:
1001 x++;
1002 setflags(FLAG_Z,!x);
1003 setflags(FLAG_N,x&0x80);
1004 break;
1005 case iny:
1006 y++;
1007 setflags(FLAG_Z,!y);
1008 setflags(FLAG_N,y&0x80);
1009 break;
1010 case jmp:
1011 wval=getmem(pc++);
1012 wval|=256*getmem(pc++);
1013 switch (addr)
1014 {
1015 case _abs:
1016 pc=wval;
1017 break;
1018 case ind:
1019 pc=getmem(wval);
1020 pc|=256*getmem(wval+1);
1021 break;
1022 }
1023 break;
1024 case jsr:
1025 push((pc+1)>>8);
1026 push((pc+1));
1027 wval=getmem(pc++);
1028 wval|=256*getmem(pc++);
1029 pc=wval;
1030 break;
1031 case lda:
1032 a=getaddr(addr);
1033 setflags(FLAG_Z,!a);
1034 setflags(FLAG_N,a&0x80);
1035 break;
1036 case ldx:
1037 x=getaddr(addr);
1038 setflags(FLAG_Z,!x);
1039 setflags(FLAG_N,x&0x80);
1040 break;
1041 case ldy:
1042 y=getaddr(addr);
1043 setflags(FLAG_Z,!y);
1044 setflags(FLAG_N,y&0x80);
1045 break;
1046 case lsr:
1047 bval=getaddr(addr); wval=(unsigned char)bval;
1048 wval>>=1;
1049 setaddr(addr,(unsigned char)wval);
1050 setflags(FLAG_Z,!wval);
1051 setflags(FLAG_N,wval&0x80);
1052 setflags(FLAG_C,bval&1);
1053 break;
1054 case _nop:
1055 break;
1056 case ora:
1057 bval=getaddr(addr);
1058 a|=bval;
1059 setflags(FLAG_Z,!a);
1060 setflags(FLAG_N,a&0x80);
1061 break;
1062 case pha:
1063 push(a);
1064 break;
1065 case php:
1066 push(p);
1067 break;
1068 case pla:
1069 a=pop();
1070 setflags(FLAG_Z,!a);
1071 setflags(FLAG_N,a&0x80);
1072 break;
1073 case plp:
1074 p=pop();
1075 break;
1076 case rol:
1077 bval=getaddr(addr);
1078 c=!!(p&FLAG_C);
1079 setflags(FLAG_C,bval&0x80);
1080 bval<<=1;
1081 bval|=c;
1082 setaddr(addr,bval);
1083 setflags(FLAG_N,bval&0x80);
1084 setflags(FLAG_Z,!bval);
1085 break;
1086 case ror:
1087 bval=getaddr(addr);
1088 c=!!(p&FLAG_C);
1089 setflags(FLAG_C,bval&1);
1090 bval>>=1;
1091 bval|=128*c;
1092 setaddr(addr,bval);
1093 setflags(FLAG_N,bval&0x80);
1094 setflags(FLAG_Z,!bval);
1095 break;
1096 case rti:
1097 /* Treat RTI like RTS */
1098 case rts:
1099 wval=pop();
1100 wval|=pop()<<8;
1101 pc=wval+1;
1102 break;
1103 case sbc:
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)));
1111 break;
1112 case sec:
1113 setflags(FLAG_C,1);
1114 break;
1115 case sed:
1116 setflags(FLAG_D,1);
1117 break;
1118 case sei:
1119 setflags(FLAG_I,1);
1120 break;
1121 case sta:
1122 putaddr(addr,a);
1123 break;
1124 case stx:
1125 putaddr(addr,x);
1126 break;
1127 case sty:
1128 putaddr(addr,y);
1129 break;
1130 case tax:
1131 x=a;
1132 setflags(FLAG_Z, !x);
1133 setflags(FLAG_N, x&0x80);
1134 break;
1135 case tay:
1136 y=a;
1137 setflags(FLAG_Z, !y);
1138 setflags(FLAG_N, y&0x80);
1139 break;
1140 case tsx:
1141 x=s;
1142 setflags(FLAG_Z, !x);
1143 setflags(FLAG_N, x&0x80);
1144 break;
1145 case txa:
1146 a=x;
1147 setflags(FLAG_Z, !a);
1148 setflags(FLAG_N, a&0x80);
1149 break;
1150 case txs:
1151 s=x;
1152 break;
1153 case tya:
1154 a=y;
1155 setflags(FLAG_Z, !a);
1156 setflags(FLAG_N, a&0x80);
1157 break;
1158 }
1159}
1160
1161void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1162void cpuJSR(unsigned short npc, unsigned char na)
1163{
1164 a=na;
1165 x=0;
1166 y=0;
1167 p=0;
1168 s=255;
1169 pc=npc;
1170 push(0);
1171 push(0);
1172
1173 while (pc > 1)
1174 cpuParse();
1175
1176}
1177
1178void c64Init(int nSampleRate) ICODE_ATTR;
1179void c64Init(int nSampleRate)
1180{
1181 synth_init(nSampleRate);
1182 memset(memory, 0, sizeof(memory));
1183
1184 cpuReset();
1185}
1186
1187
1188
1189unsigned 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;
1191unsigned 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)
1193{
1194 unsigned char *pData;
1195 unsigned char data_file_offset;
1196
1197 pData = (unsigned char*)pSidData;
1198 data_file_offset = pData[7];
1199
1200 *load_addr = pData[8]<<8;
1201 *load_addr|= pData[9];
1202
1203 *init_addr = pData[10]<<8;
1204 *init_addr|= pData[11];
1205
1206 *play_addr = pData[12]<<8;
1207 *play_addr|= pData[13];
1208
1209 *subsongs = pData[0xf]-1;
1210 *startsong = pData[0x11]-1;
1211
1212 *load_addr = pData[data_file_offset];
1213 *load_addr|= pData[data_file_offset+1]<<8;
1214
1215 *speed = pData[0x15];
1216
1217 memset(memory, 0, sizeof(memory));
1218 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1219
1220 if (*play_addr == 0)
1221 {
1222 cpuJSR(*init_addr, 0);
1223 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1224 }
1225
1226 return *load_addr;
1227}
1228
1229static int nSamplesRendered = 0;
1230static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1231static int nSamplesToRender = 0;
1232
1233/* this is the codec entry point */
1234enum codec_status codec_main(enum codec_entry_call_reason reason)
1235{
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);
1241 /* Mono output */
1242 ci->configure(DSP_SET_STEREO_MODE, STEREO_MONO);
1243 }
1244
1245 return CODEC_OK;
1246}
1247
1248/* this is called for each file to process */
1249enum codec_status codec_run(void)
1250{
1251 size_t filesize;
1252 unsigned short load_addr, init_addr, play_addr;
1253 unsigned char subSongsMax, subSong, song_speed;
1254 unsigned char *sidfile = NULL;
1255 intptr_t param;
1256
1257 if (codec_init()) {
1258 return CODEC_ERROR;
1259 }
1260
1261 codec_set_replaygain(ci->id3);
1262
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 */
1265 ci->seek_buffer(0);
1266 sidfile = ci->request_buffer(&filesize, SID_BUFFER_SIZE);
1267
1268 if (filesize == 0) {
1269 return CODEC_ERROR;
1270 }
1271
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 */
1277
1278
1279 /* Set the elapsed time to the current subsong (in seconds) */
1280 ci->set_elapsed(subSong*1000);
1281
1282 /* The main decoder loop */
1283 while (1) {
1284 enum codec_command_action action = ci->get_command(&param);
1285
1286 if (action == CODEC_ACTION_HALT)
1287 break;
1288
1289 if (action == CODEC_ACTION_SEEK_TIME) {
1290 /* New time is ready in param */
1291
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 */
1300
1301 /* Set the elapsed time to the current subsong (in seconds) */
1302 ci->set_elapsed(subSong*1000);
1303 ci->seek_complete();
1304 }
1305
1306 nSamplesRendered = 0;
1307 while (nSamplesRendered < CHUNK_SIZE)
1308 {
1309 if (nSamplesToRender == 0)
1310 {
1311 cpuJSR(play_addr, 0);
1312
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;
1319
1320 nSamplesToRender = nSamplesPerCall;
1321 }
1322 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1323 {
1324 synth_render(samples+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1325 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1326 nSamplesRendered = CHUNK_SIZE;
1327 }
1328 else
1329 {
1330 synth_render(samples+nSamplesRendered, nSamplesToRender);
1331 nSamplesRendered += nSamplesToRender;
1332 nSamplesToRender = 0;
1333 }
1334 }
1335
1336 ci->pcmbuf_insert(samples, NULL, CHUNK_SIZE);
1337 }
1338
1339 return CODEC_OK;
1340}