summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWolfram Sang <wsa@the-dreams.de>2023-01-19 22:53:26 +0100
committerSolomon Peachy <pizza@shaftnet.org>2023-02-07 09:19:32 -0500
commit70ce734ecebaca83ef9c42447666837d3fbc028e (patch)
tree80055521c945fc21c2d3b079b3380a2e776e2466
parent15c0f0576e73d714a09bcc9c09e93e80e330237d (diff)
downloadrockbox-70ce734ecebaca83ef9c42447666837d3fbc028e.tar.gz
rockbox-70ce734ecebaca83ef9c42447666837d3fbc028e.zip
codec: sid: use cRSID as a library for playing SID files
Change-Id: Iee70933e47ff8df8f26c9a63112de4da4a8e6c17
-rw-r--r--docs/CREDITS1
-rw-r--r--lib/rbcodec/codecs/cRSID/README.rockbox19
-rw-r--r--lib/rbcodec/codecs/cRSID/SOURCES1
-rw-r--r--lib/rbcodec/codecs/cRSID/cRSID.make16
-rw-r--r--lib/rbcodec/codecs/codecs.make3
-rw-r--r--lib/rbcodec/codecs/sid.c1308
6 files changed, 76 insertions, 1272 deletions
diff --git a/docs/CREDITS b/docs/CREDITS
index d44d90283e..697a32b298 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -714,6 +714,7 @@ James Le Cuirot
714Michael Landherr 714Michael Landherr
715Roman Artiukhin 715Roman Artiukhin
716Richard Goedeken 716Richard Goedeken
717Mihaly 'Hermit' Horvath
717 718
718The libmad team 719The libmad team
719The wavpack team 720The wavpack team
diff --git a/lib/rbcodec/codecs/cRSID/README.rockbox b/lib/rbcodec/codecs/cRSID/README.rockbox
new file mode 100644
index 0000000000..b95151aa09
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/README.rockbox
@@ -0,0 +1,19 @@
1Some notes about cRSID usage in Rockbox
2by Ninja (Wolfram Sang) in 2023
3
4The cRSID codebase is from v1.0. The only change made was a separation of the
5cRSID header into a public and private one, so it could be compiled as a
6library. You can find it as a separate commit in the git repository. This
7likely needs to be updated whenever a newer version of cRSID shall be used.
8
9Currently, newer versions of cRSID are available but they have been discarded.
10v1.1 mainly adds a high quality playback mode using 7x oversampling. This is
11too much for a Sansa Clip. Because the old playback mode still exists, it might
12be possible to add a runtime option to let the user choose. As a first step
13however, it was decided to give the user a working codec without having to deal
14with options. v1.2 mainly adds a SDL-based GUI player, no bigger changes in SID
15emulation. Staying with v1.0 also keeps the codec size significantly lower
16(~50KB for v1.0 vs ~90KB for v1.2 on the Sansa Clip).
17
18cRSID Releases can be found here:
19https://csdb.dk/search/?seinsel=releases&search=crsid
diff --git a/lib/rbcodec/codecs/cRSID/SOURCES b/lib/rbcodec/codecs/cRSID/SOURCES
new file mode 100644
index 0000000000..203c9dfbd1
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/SOURCES
@@ -0,0 +1 @@
libcRSID.c
diff --git a/lib/rbcodec/codecs/cRSID/cRSID.make b/lib/rbcodec/codecs/cRSID/cRSID.make
new file mode 100644
index 0000000000..2d5acb8b20
--- /dev/null
+++ b/lib/rbcodec/codecs/cRSID/cRSID.make
@@ -0,0 +1,16 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7
8# cRSID
9CRSID := $(CODECDIR)/cRSID.a
10CRSID_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/cRSID/SOURCES)
11CRSID_OBJ := $(call c2obj, $(CRSID_SRC))
12OTHER_SRC += $(CRSID_SRC)
13
14$(CRSID): $(CRSID_OBJ)
15 $(SILENT)$(shell rm -f $@)
16 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null
diff --git a/lib/rbcodec/codecs/codecs.make b/lib/rbcodec/codecs/codecs.make
index 5f3ccb52b8..bc6549498e 100644
--- a/lib/rbcodec/codecs/codecs.make
+++ b/lib/rbcodec/codecs/codecs.make
@@ -65,6 +65,7 @@ include $(RBCODECLIB_DIR)/codecs/libgme/libvgm.make
65include $(RBCODECLIB_DIR)/codecs/libgme/libkss.make 65include $(RBCODECLIB_DIR)/codecs/libgme/libkss.make
66include $(RBCODECLIB_DIR)/codecs/libgme/libemu2413.make 66include $(RBCODECLIB_DIR)/codecs/libgme/libemu2413.make
67include $(RBCODECLIB_DIR)/codecs/libopus/libopus.make 67include $(RBCODECLIB_DIR)/codecs/libopus/libopus.make
68include $(RBCODECLIB_DIR)/codecs/cRSID/cRSID.make
68 69
69# set CODECFLAGS per codec lib, since gcc takes the last -Ox and the last 70# set CODECFLAGS per codec lib, since gcc takes the last -Ox and the last
70# in a -ffoo -fno-foo pair, there is no need to filter them out 71# in a -ffoo -fno-foo pair, there is no need to filter them out
@@ -101,6 +102,7 @@ $(WAVPACKLIB) : CODECFLAGS += -O1
101$(WMALIB) : CODECFLAGS += -O2 102$(WMALIB) : CODECFLAGS += -O2
102$(WMAPROLIB) : CODECFLAGS += -O1 103$(WMAPROLIB) : CODECFLAGS += -O1
103$(WMAVOICELIB) : CODECFLAGS += -O1 104$(WMAVOICELIB) : CODECFLAGS += -O1
105$(CRSID) : CODECFLAGS += -O3
104 106
105# fine-tuning of CODECFLAGS per cpu arch 107# fine-tuning of CODECFLAGS per cpu arch
106ifeq ($(ARCH),arch_arm) 108ifeq ($(ARCH),arch_arm)
@@ -192,6 +194,7 @@ $(CODECDIR)/sgc.codec : $(CODECDIR)/libsgc.a $(CODECDIR)/libemu2413.a
192$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a $(CODECDIR)/libemu2413.a 194$(CODECDIR)/vgm.codec : $(CODECDIR)/libvgm.a $(CODECDIR)/libemu2413.a
193$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a $(CODECDIR)/libemu2413.a 195$(CODECDIR)/kss.codec : $(CODECDIR)/libkss.a $(CODECDIR)/libemu2413.a
194$(CODECDIR)/opus.codec : $(CODECDIR)/libopus.a $(TLSFLIB) 196$(CODECDIR)/opus.codec : $(CODECDIR)/libopus.a $(TLSFLIB)
197$(CODECDIR)/sid.codec : $(CODECDIR)/cRSID.a
195$(CODECDIR)/aac_bsf.codec : $(CODECDIR)/libfaad.a 198$(CODECDIR)/aac_bsf.codec : $(CODECDIR)/libfaad.a
196 199
197$(CODECS): $(CODEC_LIBS) # this must be last in codec dependency list 200$(CODECS): $(CODEC_LIBS) # this must be last in codec dependency list
diff --git a/lib/rbcodec/codecs/sid.c b/lib/rbcodec/codecs/sid.c
index 6ce11b34cb..ce6caa8198 100644
--- a/lib/rbcodec/codecs/sid.c
+++ b/lib/rbcodec/codecs/sid.c
@@ -5,13 +5,13 @@
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$
9 * 8 *
10 * SID Codec for rockbox based on the TinySID engine 9 * SID Codec for Rockbox using Hermit's cRSID library
11 *
12 * Written by Tammo Hinrichs (kb) and Rainer Sinsch in 1998-1999
13 * Ported to rockbox on 14 April 2006
14 * 10 *
11 * Written by Hermit (Mihaly Horvath) and Ninja (Wolfram Sang) in 2022/23.
12 * Some generic codec handling taken from the former SID codec done by
13 * Tammo Hinrichs, Rainer Sinsch, Dave Chapman, Stefan Waigand, Igor Poretsky,
14 * Solomon Peachy.
15 * 15 *
16 * This program is free software; you can redistribute it and/or 16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License 17 * modify it under the terms of the GNU General Public License
@@ -21,1331 +21,95 @@
21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
22 * KIND, either express or implied. 22 * KIND, either express or implied.
23 * 23 *
24 ****************************************************************************/ 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 * v1.3
59 * Added 25-07-2019: Stefan Waigand, Igor Poretsky, Solomon Peachy
60 * SID playback in stereo (See FS#11052)
61 *
62 **************************/
63
64#define USE_FILTER
65 25
66#include "debug.h" 26#include "cRSID/libcRSID.h"
67#include "codeclib.h" 27#include "codeclib.h"
68#include <inttypes.h> 28#include <inttypes.h>
69 29
70CODEC_HEADER 30CODEC_HEADER
71 31
72#define CHUNK_SIZE (1024*2) 32/* bigger CHUNK_SIZE makes Clip sluggish when playing 2SIDs */
33#define CHUNK_SIZE 512
73#define SID_BUFFER_SIZE 0x10000 34#define SID_BUFFER_SIZE 0x10000
74#define SAMPLE_RATE 44100 35#define SAMPLE_RATE 44100
75 36
76/* This codec supports SID Files:
77 *
78 */
79
80/* The sample buffers */
81static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR; 37static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR;
82static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR; 38static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR;
83 39
84void sidPoke(int reg, unsigned char val) ICODE_ATTR; 40void sid_render(int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR;
85 41void sid_render(int32_t *buffer_r, int32_t *buffer_l, unsigned long len) {
86#define FLAG_N 128
87#define FLAG_V 64
88#define FLAG_B 16
89#define FLAG_D 8
90#define FLAG_I 4
91#define FLAG_Z 2
92#define FLAG_C 1
93
94#define imp 0
95#define imm 1
96#define _abs 2
97#define absx 3
98#define absy 4
99#define zp 6
100#define zpx 7
101#define zpy 8
102#define ind 9
103#define indx 10
104#define indy 11
105#define acc 12
106#define rel 13
107
108enum {
109 adc, _and, asl, bcc, bcs, beq, bit, bmi, bne, bpl, _brk, bvc, bvs, clc,
110 cld, cli, clv, cmp, cpx, cpy, dec, dex, dey, eor, inc, inx, iny, jmp,
111 jsr, lda, ldx, ldy, lsr, _nop, ora, pha, php, pla, plp, rol, ror, rti,
112 rts, sbc, sec, sed, sei, sta, stx, sty, tax, tay, tsx, txa, txs, tya,
113 xxx
114};
115
116/* SID register definition */
117struct s6581 {
118 struct sidvoice {
119 unsigned short freq;
120 unsigned short pulse;
121 unsigned char wave;
122 unsigned char ad;
123 unsigned char sr;
124 } v[3];
125 unsigned char ffreqlo;
126 unsigned char ffreqhi;
127 unsigned char res_ftv;
128 unsigned char ftp_vol;
129};
130
131/* internal oscillator def */
132struct sidosc {
133 unsigned long freq;
134 unsigned long pulse;
135 unsigned char wave;
136 unsigned char filter;
137 unsigned long attack;
138 unsigned long decay;
139 unsigned long sustain;
140 unsigned long release;
141 unsigned long counter;
142 signed long envval;
143 unsigned char envphase;
144 unsigned long noisepos;
145 unsigned long noiseval;
146 unsigned char noiseout;
147};
148
149/* internal filter def */
150struct sidflt {
151 int freq;
152 unsigned char l_ena;
153 unsigned char b_ena;
154 unsigned char h_ena;
155 unsigned char v3ena;
156 int vol;
157 int rez;
158 int h;
159 int b;
160 int l;
161};
162
163/* ------------------------ pseudo-constants (depending on mixing freq) */
164static int mixing_frequency IDATA_ATTR;
165static unsigned long freqmul IDATA_ATTR;
166static int filtmul IDATA_ATTR;
167#ifndef ROCKBOX
168unsigned long attacks [16] IDATA_ATTR;
169unsigned long releases[16] IDATA_ATTR;
170#endif
171
172/* ------------------------------------------------------------ globals */
173static struct s6581 sid IDATA_ATTR;
174static struct sidosc osc[3] IDATA_ATTR;
175static struct sidflt filter IDATA_ATTR;
176
177/* ------------------------------------------------------ C64 Emu Stuff */
178static unsigned char bval IDATA_ATTR;
179static unsigned short wval IDATA_ATTR;
180/* -------------------------------------------------- Register & memory */
181static unsigned char a,x,y,s,p IDATA_ATTR;
182static unsigned short pc IDATA_ATTR;
183
184static unsigned char memory[65536];
185
186/* ----------------------------------------- Variables for sample stuff */
187static int sample_active IDATA_ATTR;
188static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR;
189static int fracPos IDATA_ATTR; /* Fractal position of sample */
190static int sample_period IDATA_ATTR;
191static int sample_repeats IDATA_ATTR;
192static int sample_order IDATA_ATTR;
193static int sample_nibble IDATA_ATTR;
194
195static int internal_period, internal_order, internal_start, internal_end,
196 internal_add, internal_repeat_times, internal_repeat_start IDATA_ATTR;
197
198/* ---------------------------------------------------------- constants */
199#ifndef ROCKBOX
200static const float attackTimes[16] ICONST_ATTR =
201{
202 0.0022528606, 0.0080099577, 0.0157696042, 0.0237795619,
203 0.0372963655, 0.0550684591, 0.0668330845, 0.0783473987,
204 0.0981219818, 0.244554021, 0.489108042, 0.782472742,
205 0.977715461, 2.93364701, 4.88907793, 7.82272493
206};
207static const float decayReleaseTimes[16] ICONST_ATTR =
208{
209 0.00891777693, 0.024594051, 0.0484185907, 0.0730116639, 0.114512475,
210 0.169078356, 0.205199432, 0.240551975, 0.301266125, 0.750858245,
211 1.50171551, 2.40243682, 3.00189298, 9.00721405, 15.010998, 24.0182111
212};
213#else
214#define DIV(X) ((int)(0x1000000 / (X * SAMPLE_RATE)))
215static const unsigned long attacks[16] ICONST_ATTR =
216{
217 DIV(0.0022528606), DIV(0.0080099577), DIV(0.0157696042), DIV(0.0237795619),
218 DIV(0.0372963655), DIV(0.0550684591), DIV(0.0668330845), DIV(0.0783473987),
219 DIV(0.0981219818), DIV(0.2445540210), DIV(0.4891080420), DIV(0.7824727420),
220 DIV(0.9777154610), DIV(2.9336470100), DIV(4.8890779300), DIV(7.8227249300)
221};
222static const unsigned long releases[16] ICONST_ATTR =
223{
224 DIV(0.00891777693), DIV(0.0245940510), DIV(0.0484185907), DIV(0.0730116639),
225 DIV(0.11451247500), DIV(0.1690783560), DIV(0.2051994320), DIV(0.2405519750),
226 DIV(0.30126612500), DIV(0.7508582450), DIV(1.5017155100), DIV(2.4024368200),
227 DIV(3.00189298000), DIV(9.0072140500), DIV(15.010998000), DIV(24.018211100)
228};
229#endif
230static const int opcodes[256] ICONST_ATTR = {
231 _brk,ora,xxx,xxx,xxx,ora,asl,xxx,php,ora,asl,xxx,xxx,ora,asl,xxx,
232 bpl,ora,xxx,xxx,xxx,ora,asl,xxx,clc,ora,xxx,xxx,xxx,ora,asl,xxx,
233 jsr,_and,xxx,xxx,bit,_and,rol,xxx,plp,_and,rol,xxx,bit,_and,rol,xxx,
234 bmi,_and,xxx,xxx,xxx,_and,rol,xxx,sec,_and,xxx,xxx,xxx,_and,rol,xxx,
235 rti,eor,xxx,xxx,xxx,eor,lsr,xxx,pha,eor,lsr,xxx,jmp,eor,lsr,xxx,
236 bvc,eor,xxx,xxx,xxx,eor,lsr,xxx,cli,eor,xxx,xxx,xxx,eor,lsr,xxx,
237 rts,adc,xxx,xxx,xxx,adc,ror,xxx,pla,adc,ror,xxx,jmp,adc,ror,xxx,
238 bvs,adc,xxx,xxx,xxx,adc,ror,xxx,sei,adc,xxx,xxx,xxx,adc,ror,xxx,
239 xxx,sta,xxx,xxx,sty,sta,stx,xxx,dey,xxx,txa,xxx,sty,sta,stx,xxx,
240 bcc,sta,xxx,xxx,sty,sta,stx,xxx,tya,sta,txs,xxx,xxx,sta,xxx,xxx,
241 ldy,lda,ldx,xxx,ldy,lda,ldx,xxx,tay,lda,tax,xxx,ldy,lda,ldx,xxx,
242 bcs,lda,xxx,xxx,ldy,lda,ldx,xxx,clv,lda,tsx,xxx,ldy,lda,ldx,xxx,
243 cpy,cmp,xxx,xxx,cpy,cmp,dec,xxx,iny,cmp,dex,xxx,cpy,cmp,dec,xxx,
244 bne,cmp,xxx,xxx,xxx,cmp,dec,xxx,cld,cmp,xxx,xxx,xxx,cmp,dec,xxx,
245 cpx,sbc,xxx,xxx,cpx,sbc,inc,xxx,inx,sbc,_nop,xxx,cpx,sbc,inc,xxx,
246 beq,sbc,xxx,xxx,xxx,sbc,inc,xxx,sed,sbc,xxx,xxx,xxx,sbc,inc,xxx
247};
248
249
250static const int modes[256] ICONST_ATTR = {
251 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
252 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
253 _abs,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
254 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
255 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
256 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,xxx,xxx,absx,absx,xxx,
257 imp,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,ind,_abs,_abs,xxx,
258 rel,indy,xxx,xxx,xxx,zpx,zpx,xxx,imp,absy,xxx,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,zpy,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
261 imm,indx,imm,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
262 rel,indy,xxx,xxx,zpx,zpx,zpy,xxx,imp,absy,acc,xxx,absx,absx,absy,xxx,
263 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
264 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx,
265 imm,indx,xxx,xxx,zp,zp,zp,xxx,imp,imm,acc,xxx,_abs,_abs,_abs,xxx,
266 rel,indy,xxx,xxx,zpx,zpx,zpx,xxx,imp,absy,acc,xxx,xxx,absx,absx,xxx
267};
268
269/* Routines for quick & dirty float calculation */
270
271static inline int quickfloat_ConvertFromInt(int i)
272{
273 return (i<<16);
274}
275#ifndef ROCKBOX
276static inline int quickfloat_ConvertFromFloat(float f)
277{
278 return (int)(f*(1<<16));
279}
280#else
281#define quickfloat_ConvertFromFloat(X) (int)(X*(1<<16))
282#endif
283static inline int quickfloat_Multiply(int a, int b)
284{
285 return (a>>8)*(b>>8);
286}
287static inline int quickfloat_ConvertToInt(int i)
288{
289 return (i>>16);
290}
291
292/* Get the bit from an unsigned long at a specified position */
293static inline unsigned char get_bit(unsigned long val, unsigned char b)
294{
295 return (unsigned char) ((val >> b) & 1);
296}
297
298
299static inline int GenerateDigi(int sIn)
300{
301 static int sample = 0;
302
303 if (!sample_active) return(sIn);
304
305 if ((sample_position < sample_end) && (sample_position >= sample_start))
306 {
307 sIn += sample;
308
309 fracPos += 985248/sample_period;
310
311 if (fracPos > mixing_frequency)
312 {
313 fracPos%=mixing_frequency;
314
315 // N�hstes Samples holen
316 if (sample_order == 0) {
317 sample_nibble++; // Nähstes Sample-Nibble
318 if (sample_nibble==2) {
319 sample_nibble = 0;
320 sample_position++;
321 }
322 }
323 else {
324 sample_nibble--;
325 if (sample_nibble < 0) {
326 sample_nibble=1;
327 sample_position++;
328 }
329 }
330 if (sample_repeats)
331 {
332 if (sample_position > sample_end)
333 {
334 sample_repeats--;
335 sample_position = sample_repeat_start;
336 }
337 else sample_active = 0;
338 }
339
340 sample = memory[sample_position&0xffff];
341 if (sample_nibble==1) // Hi-Nibble holen?
342 sample = (sample & 0xf0)>>4;
343 else sample = sample & 0x0f;
344
345 sample -= 7;
346 sample <<= 10;
347 }
348 }
349
350 return (sIn);
351}
352
353/* ------------------------------------------------------------- synthesis
354 initialize SID and frequency dependant values */
355void synth_init(unsigned long mixfrq) ICODE_ATTR;
356void synth_init(unsigned long mixfrq)
357{
358#ifndef ROCKBOX
359 int i;
360#endif
361 mixing_frequency = mixfrq;
362 fracPos = 0;
363 freqmul = 15872000 / mixfrq;
364 filtmul = quickfloat_ConvertFromFloat(21.5332031f)/mixfrq;
365#ifndef ROCKBOX
366 for (i=0;i<16;i++) {
367 attacks [i]=(int) (0x1000000 / (attackTimes[i]*mixfrq));
368 releases[i]=(int) (0x1000000 / (decayReleaseTimes[i]*mixfrq));
369 }
370#endif
371 memset(&sid,0,sizeof(sid));
372 memset(osc,0,sizeof(osc));
373 memset(&filter,0,sizeof(filter));
374 osc[0].noiseval = 0xffffff;
375 osc[1].noiseval = 0xffffff;
376 osc[2].noiseval = 0xffffff;
377}
378
379/* render a buffer of n samples with the actual register contents */
380void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR;
381void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len)
382{
383 unsigned long bp; 42 unsigned long bp;
384 /* step 1: convert the not easily processable sid registers into some 43 int output;
385 more convenient and fast values (makes the thing much faster
386 if you process more than 1 sample value at once) */
387 unsigned char v;
388 for (v=0;v<3;v++) {
389 osc[v].pulse = (sid.v[v].pulse & 0xfff) << 16;
390 osc[v].filter = get_bit(sid.res_ftv,v);
391 osc[v].attack = attacks[sid.v[v].ad >> 4];
392 osc[v].decay = releases[sid.v[v].ad & 0xf];
393 osc[v].sustain = sid.v[v].sr & 0xf0;
394 osc[v].release = releases[sid.v[v].sr & 0xf];
395 osc[v].wave = sid.v[v].wave;
396 osc[v].freq = ((unsigned long)sid.v[v].freq)*freqmul;
397 }
398
399#ifdef USE_FILTER
400 filter.freq = (16*sid.ffreqhi + (sid.ffreqlo&0x7)) * filtmul;
401
402 if (filter.freq>quickfloat_ConvertFromInt(1))
403 filter.freq=quickfloat_ConvertFromInt(1);
404 /* the above line isnt correct at all - the problem is that the filter
405 works only up to rmxfreq/4 - this is sufficient for 44KHz but isnt
406 for 32KHz and lower - well, but sound quality is bad enough then to
407 neglect the fact that the filter doesnt come that high ;) */
408 filter.l_ena = get_bit(sid.ftp_vol,4);
409 filter.b_ena = get_bit(sid.ftp_vol,5);
410 filter.h_ena = get_bit(sid.ftp_vol,6);
411 filter.v3ena = !get_bit(sid.ftp_vol,7);
412 filter.vol = (sid.ftp_vol & 0xf);
413 filter.rez = quickfloat_ConvertFromFloat(1.2f) -
414 quickfloat_ConvertFromFloat(0.04f)*(sid.res_ftv >> 4);
415
416 /* We precalculate part of the quick float operation, saves time in loop later */
417 filter.rez>>=8;
418#endif
419
420
421 /* now render the buffer */
422 for (bp=0;bp<len;bp++) {
423#ifdef USE_FILTER
424 int outo[2]={0,0};
425#endif
426 int outf[2]={0,0};
427 /* step 2 : generate the two output signals (for filtered and non-
428 filtered) from the osc/eg sections */
429 for (v=0;v<3;v++) {
430 /* update wave counter */
431 osc[v].counter = (osc[v].counter+osc[v].freq) & 0xFFFFFFF;
432 /* reset counter / noise generator if reset get_bit set */
433 if (osc[v].wave & 0x08) {
434 osc[v].counter = 0;
435 osc[v].noisepos = 0;
436 osc[v].noiseval = 0xffffff;
437 }
438 unsigned char refosc = v?v-1:2; /* reference oscillator for sync/ring */
439 /* sync oscillator to refosc if sync bit set */
440 if (osc[v].wave & 0x02)
441 if (osc[refosc].counter < osc[refosc].freq)
442 osc[v].counter = osc[refosc].counter * osc[v].freq / osc[refosc].freq;
443 /* generate waveforms with really simple algorithms */
444 unsigned char triout = (unsigned char) (osc[v].counter>>19);
445 if (osc[v].counter>>27)
446 triout^=0xff;
447 unsigned char sawout = (unsigned char) (osc[v].counter >> 20);
448 unsigned char plsout = (unsigned char) ((osc[v].counter > osc[v].pulse)-1);
449
450 /* generate noise waveform exactly as the SID does. */
451 if (osc[v].noisepos!=(osc[v].counter>>23))
452 {
453 osc[v].noisepos = osc[v].counter >> 23;
454 osc[v].noiseval = (osc[v].noiseval << 1) |
455 (get_bit(osc[v].noiseval,22) ^ get_bit(osc[v].noiseval,17));
456 osc[v].noiseout = (get_bit(osc[v].noiseval,22) << 7) |
457 (get_bit(osc[v].noiseval,20) << 6) |
458 (get_bit(osc[v].noiseval,16) << 5) |
459 (get_bit(osc[v].noiseval,13) << 4) |
460 (get_bit(osc[v].noiseval,11) << 3) |
461 (get_bit(osc[v].noiseval, 7) << 2) |
462 (get_bit(osc[v].noiseval, 4) << 1) |
463 (get_bit(osc[v].noiseval, 2) << 0);
464 }
465 unsigned char nseout = osc[v].noiseout;
466
467 /* modulate triangle wave if ringmod bit set */
468 if (osc[v].wave & 0x04)
469 if (osc[refosc].counter < 0x8000000)
470 triout ^= 0xff;
471
472 /* now mix the oscillators with an AND operation as stated in
473 the SID's reference manual - even if this is completely wrong.
474 well, at least, the $30 and $70 waveform sounds correct and there's
475 no real solution to do $50 and $60, so who cares. */
476
477 unsigned char outv=0xFF;
478 if (osc[v].wave & 0x10) outv &= triout;
479 if (osc[v].wave & 0x20) outv &= sawout;
480 if (osc[v].wave & 0x40) outv &= plsout;
481 if (osc[v].wave & 0x80) outv &= nseout;
482
483 /* so now process the volume according to the phase and adsr values */
484 switch (osc[v].envphase) {
485 case 0 : { /* Phase 0 : Attack */
486 osc[v].envval+=osc[v].attack;
487 if (osc[v].envval >= 0xFFFFFF)
488 {
489 osc[v].envval = 0xFFFFFF;
490 osc[v].envphase = 1;
491 }
492 break;
493 }
494 case 1 : { /* Phase 1 : Decay */
495 osc[v].envval-=osc[v].decay;
496 if ((signed int) osc[v].envval <= (signed int) (osc[v].sustain<<16))
497 {
498 osc[v].envval = osc[v].sustain<<16;
499 osc[v].envphase = 2;
500 }
501 break;
502 }
503 case 2 : { /* Phase 2 : Sustain */
504 if ((signed int) osc[v].envval != (signed int) (osc[v].sustain<<16))
505 {
506 osc[v].envphase = 1;
507 }
508 /* :) yes, thats exactly how the SID works. and maybe
509 a music routine out there supports this, so better
510 let it in, thanks :) */
511 break;
512 }
513 case 3 : { /* Phase 3 : Release */
514 osc[v].envval-=osc[v].release;
515 if (osc[v].envval < 0x40000) osc[v].envval= 0x40000;
516
517 /* the volume offset is because the SID does not
518 completely silence the voices when it should. most
519 emulators do so though and thats the main reason
520 why the sound of emulators is too, err... emulated :) */
521 break;
522 }
523 }
524
525#ifdef USE_FILTER
526
527 /* now route the voice output to either the non-filtered or the
528 filtered channel and dont forget to blank out osc3 if desired */
529
530 if (v<2 || filter.v3ena)
531 {
532 if (osc[v].filter)
533 outf[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
534 else
535 outo[v&1]+=(((int)(outv-0x80))*osc[v].envval)>>22;
536 }
537#else /* !USE_FILTER */
538 /* Don't use filters, just mix voices together */
539 outf[v&1]+=((signed short)(outv-0x80)) * (osc[v].envval>>4);
540#endif
541 } /* for (v=0;v<3;v++) */
542
543
544#ifdef USE_FILTER
545 /* step 3
546 * so, now theres finally time to apply the multi-mode resonant filter
547 * to the signal. The easiest thing ist just modelling a real electronic
548 * filter circuit instead of fiddling around with complex IIRs or even
549 * FIRs ...
550 * it sounds as good as them or maybe better and needs only 3 MULs and
551 * 4 ADDs for EVERYTHING. SIDPlay uses this kind of filter, too, but
552 * Mage messed the whole thing completely up - as the rest of the
553 * emulator.
554 * This filter sounds a lot like the 8580, as the low-quality, dirty
555 * sound of the 6581 is uuh too hard to achieve :) */
556
557 for (v=0;v<2;v++) { /* do step 3 for both channels */
558 filter.h = quickfloat_ConvertFromInt(outf[v]) - (filter.b>>8)*filter.rez - filter.l;
559 filter.b += quickfloat_Multiply(filter.freq, filter.h);
560 filter.l += quickfloat_Multiply(filter.freq, filter.b);
561
562 outf[v] = 0;
563
564 if (filter.l_ena) outf[v]+=quickfloat_ConvertToInt(filter.l);
565 if (filter.b_ena) outf[v]+=quickfloat_ConvertToInt(filter.b);
566 if (filter.h_ena) outf[v]+=quickfloat_ConvertToInt(filter.h);
567 }
568
569 /* mix in other channel to reduce stereo panning for better sound on headphones */
570 int final_sample_r = filter.vol*((outo[0]+outf[0]) + ((outo[1]+outf[1])>>4));
571 int final_sample_l = filter.vol*((outo[1]+outf[1]) + ((outo[0]+outf[0])>>4));
572 *(buffer_r+bp)= GenerateDigi(final_sample_r)<<13;
573 *(buffer_l+bp)= GenerateDigi(final_sample_l)<<13;
574#else /* !USE_FILTER */
575 *(buffer_r+bp) = GenerateDigi(outf[0])<<3;
576 *(buffer_l+bp) = GenerateDigi(outf[1])<<3;
577#endif
578 } /*for (bp=0;bp<len;bp++) */
579}
580
581
582
583/*
584* C64 Mem Routines
585*/
586static inline unsigned char getmem(unsigned short addr)
587{
588 return memory[addr];
589}
590
591static inline void setmem(unsigned short addr, unsigned char value)
592{
593 if ((addr&0xfc00)==0xd400)
594 {
595 sidPoke(addr&0x1f,value);
596 /* New SID-Register */
597 if (addr > 0xd418)
598 {
599 switch (addr)
600 {
601 case 0xd41f: /* Start-Hi */
602 internal_start = (internal_start&0x00ff) | (value<<8); break;
603 case 0xd41e: /* Start-Lo */
604 internal_start = (internal_start&0xff00) | (value); break;
605 case 0xd47f: /* Repeat-Hi */
606 internal_repeat_start = (internal_repeat_start&0x00ff) | (value<<8); break;
607 case 0xd47e: /* Repeat-Lo */
608 internal_repeat_start = (internal_repeat_start&0xff00) | (value); break;
609 case 0xd43e: /* End-Hi */
610 internal_end = (internal_end&0x00ff) | (value<<8); break;
611 case 0xd43d: /* End-Lo */
612 internal_end = (internal_end&0xff00) | (value); break;
613 case 0xd43f: /* Loop-Size */
614 internal_repeat_times = value; break;
615 case 0xd45e: /* Period-Hi */
616 internal_period = (internal_period&0x00ff) | (value<<8); break;
617 case 0xd45d: /* Period-Lo */
618 internal_period = (internal_period&0xff00) | (value); break;
619 case 0xd47d: /* Sample Order */
620 internal_order = value; break;
621 case 0xd45f: /* Sample Add */
622 internal_add = value; break;
623 case 0xd41d: /* Start sampling */
624 sample_repeats = internal_repeat_times;
625 sample_position = internal_start;
626 sample_start = internal_start;
627 sample_end = internal_end;
628 sample_repeat_start = internal_repeat_start;
629 sample_period = internal_period;
630 sample_order = internal_order;
631 switch (value)
632 {
633 case 0xfd: sample_active = 0; break;
634 case 0xfe:
635 case 0xff: sample_active = 1; break;
636 default: return;
637 }
638 break;
639 }
640 }
641 }
642 else memory[addr]=value;
643}
644
645/*
646* Poke a value into the sid register
647*/
648void sidPoke(int reg, unsigned char val) ICODE_ATTR;
649void sidPoke(int reg, unsigned char val)
650{
651 int voice=0;
652
653 if ((reg >= 7) && (reg <=13)) {voice=1; reg-=7;}
654 else if ((reg >= 14) && (reg <=20)) {voice=2; reg-=14;}
655
656 switch (reg) {
657 case 0: { /* Set frequency: Low byte */
658 sid.v[voice].freq = (sid.v[voice].freq&0xff00)+val;
659 break;
660 }
661 case 1: { /* Set frequency: High byte */
662 sid.v[voice].freq = (sid.v[voice].freq&0xff)+(val<<8);
663 break;
664 }
665 case 2: { /* Set pulse width: Low byte */
666 sid.v[voice].pulse = (sid.v[voice].pulse&0xff00)+val;
667 break;
668 }
669 case 3: { /* Set pulse width: High byte */
670 sid.v[voice].pulse = (sid.v[voice].pulse&0xff)+(val<<8);
671 break;
672 }
673 case 4: { sid.v[voice].wave = val;
674 /* Directly look at GATE-Bit!
675 * a change may happen twice or more often during one cpujsr
676 * Put the Envelope Generator into attack or release phase if desired
677 */
678 if ((val & 0x01) == 0) osc[voice].envphase=3;
679 else if (osc[voice].envphase==3) osc[voice].envphase=0;
680 break;
681 }
682
683 case 5: { sid.v[voice].ad = val; break;}
684 case 6: { sid.v[voice].sr = val; break;}
685
686 case 21: { sid.ffreqlo = val; break; }
687 case 22: { sid.ffreqhi = val; break; }
688 case 23: { sid.res_ftv = val; break; }
689 case 24: { sid.ftp_vol = val; break;}
690 }
691 return;
692}
693
694static inline unsigned char getaddr(int mode)
695{
696 unsigned short ad,ad2;
697 switch(mode)
698 {
699 case imp:
700 return 0;
701 case imm:
702 return getmem(pc++);
703 case _abs:
704 ad=getmem(pc++);
705 ad|=256*getmem(pc++);
706 return getmem(ad);
707 case absx:
708 ad=getmem(pc++);
709 ad|=256*getmem(pc++);
710 ad2=ad+x;
711 return getmem(ad2);
712 case absy:
713 ad=getmem(pc++);
714 ad|=256*getmem(pc++);
715 ad2=ad+y;
716 return getmem(ad2);
717 case zp:
718 ad=getmem(pc++);
719 return getmem(ad);
720 case zpx:
721 ad=getmem(pc++);
722 ad+=x;
723 return getmem(ad&0xff);
724 case zpy:
725 ad=getmem(pc++);
726 ad+=y;
727 return getmem(ad&0xff);
728 case indx:
729 ad=getmem(pc++);
730 ad+=x;
731 ad2=getmem(ad&0xff);
732 ad++;
733 ad2|=getmem(ad&0xff)<<8;
734 return getmem(ad2);
735 case indy:
736 ad=getmem(pc++);
737 ad2=getmem(ad);
738 ad2|=getmem((ad+1)&0xff)<<8;
739 ad=ad2+y;
740 return getmem(ad);
741 case acc:
742 return a;
743 }
744 return 0;
745}
746
747static inline void setaddr(int mode, unsigned char val)
748{
749 unsigned short ad,ad2;
750 switch(mode)
751 {
752 case _abs:
753 ad=getmem(pc-2);
754 ad|=256*getmem(pc-1);
755 setmem(ad,val);
756 return;
757 case absx:
758 ad=getmem(pc-2);
759 ad|=256*getmem(pc-1);
760 ad2=ad+x;
761 setmem(ad2,val);
762 return;
763 case zp:
764 ad=getmem(pc-1);
765 setmem(ad,val);
766 return;
767 case zpx:
768 ad=getmem(pc-1);
769 ad+=x;
770 setmem(ad&0xff,val);
771 return;
772 case acc:
773 a=val;
774 return;
775 }
776}
777
778
779static inline void putaddr(int mode, unsigned char val)
780{
781 unsigned short ad,ad2;
782 switch(mode)
783 {
784 case _abs:
785 ad=getmem(pc++);
786 ad|=getmem(pc++)<<8;
787 setmem(ad,val);
788 return;
789 case absx:
790 ad=getmem(pc++);
791 ad|=getmem(pc++)<<8;
792 ad2=ad+x;
793 setmem(ad2,val);
794 return;
795 case absy:
796 ad=getmem(pc++);
797 ad|=getmem(pc++)<<8;
798 ad2=ad+y;
799 setmem(ad2,val);
800 return;
801 case zp:
802 ad=getmem(pc++);
803 setmem(ad,val);
804 return;
805 case zpx:
806 ad=getmem(pc++);
807 ad+=x;
808 setmem(ad&0xff,val);
809 return;
810 case zpy:
811 ad=getmem(pc++);
812 ad+=y;
813 setmem(ad&0xff,val);
814 return;
815 case indx:
816 ad=getmem(pc++);
817 ad+=x;
818 ad2=getmem(ad&0xff);
819 ad++;
820 ad2|=getmem(ad&0xff)<<8;
821 setmem(ad2,val);
822 return;
823 case indy:
824 ad=getmem(pc++);
825 ad2=getmem(ad);
826 ad2|=getmem((ad+1)&0xff)<<8;
827 ad=ad2+y;
828 setmem(ad,val);
829 return;
830 case acc:
831 a=val;
832 return;
833 }
834}
835
836
837static inline void setflags(int flag, int cond)
838{
839 if (cond) p|=flag;
840 else p&=~flag;
841}
842
843
844static inline void push(unsigned char val)
845{
846 setmem(0x100+s,val);
847 if (s) s--;
848}
849
850static inline unsigned char pop(void)
851{
852 if (s<0xff) s++;
853 return getmem(0x100+s);
854}
855
856static inline void branch(int flag)
857{
858 signed char dist;
859 dist=(signed char)getaddr(imm);
860 wval=pc+dist;
861 if (flag) pc=wval;
862}
863 44
864void cpuReset(void) ICODE_ATTR; 45 for (bp = 0; bp < len; bp++) {
865void cpuReset(void) 46 output = cRSID_generateSample(&cRSID_C64) << 12;
866{ 47 *(buffer_r + bp) = output; *(buffer_l + bp) = output;
867 a=x=y=0;
868 p=0;
869 s=255;
870 pc=getaddr(0xfffc);
871}
872
873void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR;
874void cpuResetTo(unsigned short npc, unsigned char na)
875{
876 a=na;
877 x=0;
878 y=0;
879 p=0;
880 s=255;
881 pc=npc;
882}
883
884static inline void cpuParse(void)
885{
886 unsigned char opc=getmem(pc++);
887 int cmd=opcodes[opc];
888 int addr=modes[opc];
889 int c;
890 switch (cmd)
891 {
892 case adc:
893 wval=(unsigned short)a+getaddr(addr)+((p&FLAG_C)?1:0);
894 setflags(FLAG_C, wval&0x100);
895 a=(unsigned char)wval;
896 setflags(FLAG_Z, !a);
897 setflags(FLAG_N, a&0x80);
898 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
899 break;
900 case _and:
901 bval=getaddr(addr);
902 a&=bval;
903 setflags(FLAG_Z, !a);
904 setflags(FLAG_N, a&0x80);
905 break;
906 case asl:
907 wval=getaddr(addr);
908 wval<<=1;
909 setaddr(addr,(unsigned char)wval);
910 setflags(FLAG_Z,!wval);
911 setflags(FLAG_N,wval&0x80);
912 setflags(FLAG_C,wval&0x100);
913 break;
914 case bcc:
915 branch(!(p&FLAG_C));
916 break;
917 case bcs:
918 branch(p&FLAG_C);
919 break;
920 case bne:
921 branch(!(p&FLAG_Z));
922 break;
923 case beq:
924 branch(p&FLAG_Z);
925 break;
926 case bpl:
927 branch(!(p&FLAG_N));
928 break;
929 case bmi:
930 branch(p&FLAG_N);
931 break;
932 case bvc:
933 branch(!(p&FLAG_V));
934 break;
935 case bvs:
936 branch(p&FLAG_V);
937 break;
938 case bit:
939 bval=getaddr(addr);
940 setflags(FLAG_Z,!(a&bval));
941 setflags(FLAG_N,bval&0x80);
942 setflags(FLAG_V,bval&0x40);
943 break;
944 case _brk:
945 pc=0; /* Just quit the emulation */
946 break;
947 case clc:
948 setflags(FLAG_C,0);
949 break;
950 case cld:
951 setflags(FLAG_D,0);
952 break;
953 case cli:
954 setflags(FLAG_I,0);
955 break;
956 case clv:
957 setflags(FLAG_V,0);
958 break;
959 case cmp:
960 bval=getaddr(addr);
961 wval=(unsigned short)a-bval;
962 setflags(FLAG_Z,!wval);
963 setflags(FLAG_N,wval&0x80);
964 setflags(FLAG_C,a>=bval);
965 break;
966 case cpx:
967 bval=getaddr(addr);
968 wval=(unsigned short)x-bval;
969 setflags(FLAG_Z,!wval);
970 setflags(FLAG_N,wval&0x80);
971 setflags(FLAG_C,x>=bval);
972 break;
973 case cpy:
974 bval=getaddr(addr);
975 wval=(unsigned short)y-bval;
976 setflags(FLAG_Z,!wval);
977 setflags(FLAG_N,wval&0x80);
978 setflags(FLAG_C,y>=bval);
979 break;
980 case dec:
981 bval=getaddr(addr);
982 bval--;
983 setaddr(addr,bval);
984 setflags(FLAG_Z,!bval);
985 setflags(FLAG_N,bval&0x80);
986 break;
987 case dex:
988 x--;
989 setflags(FLAG_Z,!x);
990 setflags(FLAG_N,x&0x80);
991 break;
992 case dey:
993 y--;
994 setflags(FLAG_Z,!y);
995 setflags(FLAG_N,y&0x80);
996 break;
997 case eor:
998 bval=getaddr(addr);
999 a^=bval;
1000 setflags(FLAG_Z,!a);
1001 setflags(FLAG_N,a&0x80);
1002 break;
1003 case inc:
1004 bval=getaddr(addr);
1005 bval++;
1006 setaddr(addr,bval);
1007 setflags(FLAG_Z,!bval);
1008 setflags(FLAG_N,bval&0x80);
1009 break;
1010 case inx:
1011 x++;
1012 setflags(FLAG_Z,!x);
1013 setflags(FLAG_N,x&0x80);
1014 break;
1015 case iny:
1016 y++;
1017 setflags(FLAG_Z,!y);
1018 setflags(FLAG_N,y&0x80);
1019 break;
1020 case jmp:
1021 wval=getmem(pc++);
1022 wval|=256*getmem(pc++);
1023 switch (addr)
1024 {
1025 case _abs:
1026 pc=wval;
1027 break;
1028 case ind:
1029 pc=getmem(wval);
1030 pc|=256*getmem(wval+1);
1031 break;
1032 }
1033 break;
1034 case jsr:
1035 push((pc+1)>>8);
1036 push((pc+1));
1037 wval=getmem(pc++);
1038 wval|=256*getmem(pc++);
1039 pc=wval;
1040 break;
1041 case lda:
1042 a=getaddr(addr);
1043 setflags(FLAG_Z,!a);
1044 setflags(FLAG_N,a&0x80);
1045 break;
1046 case ldx:
1047 x=getaddr(addr);
1048 setflags(FLAG_Z,!x);
1049 setflags(FLAG_N,x&0x80);
1050 break;
1051 case ldy:
1052 y=getaddr(addr);
1053 setflags(FLAG_Z,!y);
1054 setflags(FLAG_N,y&0x80);
1055 break;
1056 case lsr:
1057 bval=getaddr(addr); wval=(unsigned char)bval;
1058 wval>>=1;
1059 setaddr(addr,(unsigned char)wval);
1060 setflags(FLAG_Z,!wval);
1061 setflags(FLAG_N,wval&0x80);
1062 setflags(FLAG_C,bval&1);
1063 break;
1064 case _nop:
1065 break;
1066 case ora:
1067 bval=getaddr(addr);
1068 a|=bval;
1069 setflags(FLAG_Z,!a);
1070 setflags(FLAG_N,a&0x80);
1071 break;
1072 case pha:
1073 push(a);
1074 break;
1075 case php:
1076 push(p);
1077 break;
1078 case pla:
1079 a=pop();
1080 setflags(FLAG_Z,!a);
1081 setflags(FLAG_N,a&0x80);
1082 break;
1083 case plp:
1084 p=pop();
1085 break;
1086 case rol:
1087 bval=getaddr(addr);
1088 c=!!(p&FLAG_C);
1089 setflags(FLAG_C,bval&0x80);
1090 bval<<=1;
1091 bval|=c;
1092 setaddr(addr,bval);
1093 setflags(FLAG_N,bval&0x80);
1094 setflags(FLAG_Z,!bval);
1095 break;
1096 case ror:
1097 bval=getaddr(addr);
1098 c=!!(p&FLAG_C);
1099 setflags(FLAG_C,bval&1);
1100 bval>>=1;
1101 bval|=128*c;
1102 setaddr(addr,bval);
1103 setflags(FLAG_N,bval&0x80);
1104 setflags(FLAG_Z,!bval);
1105 break;
1106 case rti:
1107 /* Treat RTI like RTS */
1108 case rts:
1109 wval=pop();
1110 wval|=pop()<<8;
1111 pc=wval+1;
1112 break;
1113 case sbc:
1114 bval=getaddr(addr)^0xff;
1115 wval=(unsigned short)a+bval+((p&FLAG_C)?1:0);
1116 setflags(FLAG_C, wval&0x100);
1117 a=(unsigned char)wval;
1118 setflags(FLAG_Z, !a);
1119 setflags(FLAG_N, a>127);
1120 setflags(FLAG_V, (!!(p&FLAG_C)) ^ (!!(p&FLAG_N)));
1121 break;
1122 case sec:
1123 setflags(FLAG_C,1);
1124 break;
1125 case sed:
1126 setflags(FLAG_D,1);
1127 break;
1128 case sei:
1129 setflags(FLAG_I,1);
1130 break;
1131 case sta:
1132 putaddr(addr,a);
1133 break;
1134 case stx:
1135 putaddr(addr,x);
1136 break;
1137 case sty:
1138 putaddr(addr,y);
1139 break;
1140 case tax:
1141 x=a;
1142 setflags(FLAG_Z, !x);
1143 setflags(FLAG_N, x&0x80);
1144 break;
1145 case tay:
1146 y=a;
1147 setflags(FLAG_Z, !y);
1148 setflags(FLAG_N, y&0x80);
1149 break;
1150 case tsx:
1151 x=s;
1152 setflags(FLAG_Z, !x);
1153 setflags(FLAG_N, x&0x80);
1154 break;
1155 case txa:
1156 a=x;
1157 setflags(FLAG_Z, !a);
1158 setflags(FLAG_N, a&0x80);
1159 break;
1160 case txs:
1161 s=x;
1162 break;
1163 case tya:
1164 a=y;
1165 setflags(FLAG_Z, !a);
1166 setflags(FLAG_N, a&0x80);
1167 break;
1168 }
1169}
1170
1171void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR;
1172void cpuJSR(unsigned short npc, unsigned char na)
1173{
1174 a=na;
1175 x=0;
1176 y=0;
1177 p=0;
1178 s=255;
1179 pc=npc;
1180 push(0);
1181 push(0);
1182
1183 while (pc > 1)
1184 cpuParse();
1185
1186}
1187
1188void c64Init(int nSampleRate) ICODE_ATTR;
1189void c64Init(int nSampleRate)
1190{
1191 synth_init(nSampleRate);
1192 memset(memory, 0, sizeof(memory));
1193
1194 cpuReset();
1195}
1196
1197
1198
1199unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1200 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size) ICODE_ATTR;
1201unsigned short LoadSIDFromMemory(void *pSidData, unsigned short *load_addr,
1202 unsigned short *init_addr, unsigned short *play_addr, unsigned char *subsongs, unsigned char *startsong, unsigned char *speed, unsigned short size)
1203{
1204 unsigned char *pData;
1205 unsigned char data_file_offset;
1206
1207 pData = (unsigned char*)pSidData;
1208 data_file_offset = pData[7];
1209
1210 *load_addr = pData[8]<<8;
1211 *load_addr|= pData[9];
1212
1213 *init_addr = pData[10]<<8;
1214 *init_addr|= pData[11];
1215
1216 *play_addr = pData[12]<<8;
1217 *play_addr|= pData[13];
1218
1219 *subsongs = pData[0xf]-1;
1220 *startsong = pData[0x11]-1;
1221
1222 *load_addr = pData[data_file_offset];
1223 *load_addr|= pData[data_file_offset+1]<<8;
1224
1225 *speed = pData[0x15];
1226
1227 memset(memory, 0, sizeof(memory));
1228 memcpy(&memory[*load_addr], &pData[data_file_offset+2], size-(data_file_offset+2));
1229
1230 if (*play_addr == 0)
1231 {
1232 cpuJSR(*init_addr, 0);
1233 *play_addr = (memory[0x0315]<<8)+memory[0x0314];
1234 } 48 }
1235
1236 return *load_addr;
1237} 49}
1238 50
1239static int nSamplesRendered = 0;
1240static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */
1241static int nSamplesToRender = 0;
1242
1243/* this is the codec entry point */
1244enum codec_status codec_main(enum codec_entry_call_reason reason) 51enum codec_status codec_main(enum codec_entry_call_reason reason)
1245{ 52{
1246 if (reason == CODEC_LOAD) { 53 if (reason == CODEC_LOAD) {
1247 /* Make use of 44.1khz */
1248 ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE); 54 ci->configure(DSP_SET_FREQUENCY, SAMPLE_RATE);
1249 /* Sample depth is 28 bit host endian */
1250 ci->configure(DSP_SET_SAMPLE_DEPTH, 28); 55 ci->configure(DSP_SET_SAMPLE_DEPTH, 28);
1251 /* Stereo output */
1252 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED); 56 ci->configure(DSP_SET_STEREO_MODE, STEREO_NONINTERLEAVED);
57 cRSID_init(SAMPLE_RATE, CHUNK_SIZE);
1253 } 58 }
1254 59
1255 return CODEC_OK; 60 return CODEC_OK;
1256} 61}
1257 62
1258/* this is called for each file to process */
1259enum codec_status codec_run(void) 63enum codec_status codec_run(void)
1260{ 64{
65
66 cRSID_SIDheader *SIDheader;
1261 size_t filesize; 67 size_t filesize;
1262 unsigned short load_addr, init_addr, play_addr; 68 unsigned char subSong;
1263 unsigned char subSongsMax, subSong, song_speed;
1264 unsigned char *sidfile = NULL; 69 unsigned char *sidfile = NULL;
1265 intptr_t param; 70 intptr_t param;
1266 bool resume; 71 bool resume;
72 long action;
1267 73
1268 if (codec_init()) { 74 if (codec_init())
1269 return CODEC_ERROR; 75 return CODEC_ERROR;
1270 }
1271 76
1272 codec_set_replaygain(ci->id3); 77 codec_set_replaygain(ci->id3);
1273 78
1274 /* Load SID file the read_filebuf callback will return the full requested
1275 * size if at all possible, so there is no need to loop */
1276 ci->seek_buffer(0); 79 ci->seek_buffer(0);
1277 sidfile = ci->request_buffer(&filesize, SID_BUFFER_SIZE); 80 sidfile = ci->request_buffer(&filesize, SID_BUFFER_SIZE);
1278 81 if (filesize == 0)
1279 if (filesize == 0) {
1280 return CODEC_ERROR; 82 return CODEC_ERROR;
1281 }
1282 83
1283 param = ci->id3->elapsed; 84 param = ci->id3->elapsed;
1284 resume = param != 0; 85 resume = param != 0;
1285 86
1286 goto sid_start; 87 /* Start first song */
1287 88 action = CODEC_ACTION_SEEK_TIME;
1288 /* The main decoder loop */
1289 while (1) {
1290 long action = ci->get_command(&param);
1291
1292 if (action == CODEC_ACTION_HALT)
1293 break;
1294 89
90 while (action != CODEC_ACTION_HALT) {
1295 if (action == CODEC_ACTION_SEEK_TIME) { 91 if (action == CODEC_ACTION_SEEK_TIME) {
1296 sid_start:
1297 /* New time is ready in param */
1298
1299 /* Start playing from scratch */ 92 /* Start playing from scratch */
1300 c64Init(SAMPLE_RATE); 93 SIDheader = cRSID_processSIDfile(&cRSID_C64, sidfile, filesize);
1301 LoadSIDFromMemory(sidfile, &load_addr, &init_addr, &play_addr, 94 subSong = SIDheader->DefaultSubtune - 1;
1302 &subSongsMax, &subSong, &song_speed, 95
1303 (unsigned short)filesize); 96 /* Now use the current seek time in seconds as subsong */
1304 sidPoke(24, 15); /* Turn on full volume */
1305 if (!resume || (resume && param)) 97 if (!resume || (resume && param))
1306 subSong = param / 1000; /* Now use the current seek time in 98 subSong = param / 1000;
1307 seconds as subsong */
1308 cpuJSR(init_addr, subSong); /* Start the song initialize */
1309 nSamplesToRender = 0; /* Start the rendering from scratch */
1310 99
1311 /* Set the elapsed time to the current subsong (in seconds) */ 100 /* Set the elapsed time to the current subsong (in seconds) */
1312 ci->set_elapsed(subSong*1000); 101 ci->set_elapsed(subSong * 1000);
1313 ci->seek_complete(); 102 ci->seek_complete();
1314
1315 resume = false; 103 resume = false;
1316 }
1317
1318 nSamplesRendered = 0;
1319 while (nSamplesRendered < CHUNK_SIZE)
1320 {
1321 if (nSamplesToRender == 0)
1322 {
1323 cpuJSR(play_addr, 0);
1324 104
1325 /* Find out if cia timing is used and how many samples 105 cRSID_initSIDtune(&cRSID_C64, SIDheader, subSong + 1);
1326 have to be calculated for each cpujsr */
1327 int nRefreshCIA = (int)(20000*(memory[0xdc04]|(memory[0xdc05]<<8))/0x4c00);
1328 if ((nRefreshCIA==0) || (song_speed == 0))
1329 nRefreshCIA = 20000;
1330 nSamplesPerCall = mixing_frequency*nRefreshCIA/1000000;
1331
1332 nSamplesToRender = nSamplesPerCall;
1333 }
1334 if (nSamplesRendered + nSamplesToRender > CHUNK_SIZE)
1335 {
1336 synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, CHUNK_SIZE-nSamplesRendered);
1337 nSamplesToRender -= CHUNK_SIZE-nSamplesRendered;
1338 nSamplesRendered = CHUNK_SIZE;
1339 }
1340 else
1341 {
1342 synth_render(samples_r+nSamplesRendered, samples_l+nSamplesRendered, nSamplesToRender);
1343 nSamplesRendered += nSamplesToRender;
1344 nSamplesToRender = 0;
1345 }
1346 } 106 }
1347 107
108 sid_render(samples_r, samples_l, CHUNK_SIZE);
1348 ci->pcmbuf_insert(samples_r, samples_l, CHUNK_SIZE); 109 ci->pcmbuf_insert(samples_r, samples_l, CHUNK_SIZE);
110
111 /* New time is in param */
112 action = ci->get_command(&param);
1349 } 113 }
1350 114
1351 return CODEC_OK; 115 return CODEC_OK;