diff options
author | Wolfram Sang <wsa@the-dreams.de> | 2023-01-19 22:53:26 +0100 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2023-02-07 09:19:32 -0500 |
commit | 70ce734ecebaca83ef9c42447666837d3fbc028e (patch) | |
tree | 80055521c945fc21c2d3b079b3380a2e776e2466 /lib | |
parent | 15c0f0576e73d714a09bcc9c09e93e80e330237d (diff) | |
download | rockbox-70ce734ecebaca83ef9c42447666837d3fbc028e.tar.gz rockbox-70ce734ecebaca83ef9c42447666837d3fbc028e.zip |
codec: sid: use cRSID as a library for playing SID files
Change-Id: Iee70933e47ff8df8f26c9a63112de4da4a8e6c17
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rbcodec/codecs/cRSID/README.rockbox | 19 | ||||
-rw-r--r-- | lib/rbcodec/codecs/cRSID/SOURCES | 1 | ||||
-rw-r--r-- | lib/rbcodec/codecs/cRSID/cRSID.make | 16 | ||||
-rw-r--r-- | lib/rbcodec/codecs/codecs.make | 3 | ||||
-rw-r--r-- | lib/rbcodec/codecs/sid.c | 1308 |
5 files changed, 75 insertions, 1272 deletions
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 @@ | |||
1 | Some notes about cRSID usage in Rockbox | ||
2 | by Ninja (Wolfram Sang) in 2023 | ||
3 | |||
4 | The cRSID codebase is from v1.0. The only change made was a separation of the | ||
5 | cRSID header into a public and private one, so it could be compiled as a | ||
6 | library. You can find it as a separate commit in the git repository. This | ||
7 | likely needs to be updated whenever a newer version of cRSID shall be used. | ||
8 | |||
9 | Currently, newer versions of cRSID are available but they have been discarded. | ||
10 | v1.1 mainly adds a high quality playback mode using 7x oversampling. This is | ||
11 | too much for a Sansa Clip. Because the old playback mode still exists, it might | ||
12 | be possible to add a runtime option to let the user choose. As a first step | ||
13 | however, it was decided to give the user a working codec without having to deal | ||
14 | with options. v1.2 mainly adds a SDL-based GUI player, no bigger changes in SID | ||
15 | emulation. 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 | |||
18 | cRSID Releases can be found here: | ||
19 | https://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 | ||
9 | CRSID := $(CODECDIR)/cRSID.a | ||
10 | CRSID_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/cRSID/SOURCES) | ||
11 | CRSID_OBJ := $(call c2obj, $(CRSID_SRC)) | ||
12 | OTHER_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 | |||
65 | include $(RBCODECLIB_DIR)/codecs/libgme/libkss.make | 65 | include $(RBCODECLIB_DIR)/codecs/libgme/libkss.make |
66 | include $(RBCODECLIB_DIR)/codecs/libgme/libemu2413.make | 66 | include $(RBCODECLIB_DIR)/codecs/libgme/libemu2413.make |
67 | include $(RBCODECLIB_DIR)/codecs/libopus/libopus.make | 67 | include $(RBCODECLIB_DIR)/codecs/libopus/libopus.make |
68 | include $(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 |
106 | ifeq ($(ARCH),arch_arm) | 108 | ifeq ($(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 | ||
70 | CODEC_HEADER | 30 | CODEC_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 */ | ||
81 | static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR; | 37 | static int32_t samples_r[CHUNK_SIZE] IBSS_ATTR; |
82 | static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR; | 38 | static int32_t samples_l[CHUNK_SIZE] IBSS_ATTR; |
83 | 39 | ||
84 | void sidPoke(int reg, unsigned char val) ICODE_ATTR; | 40 | void sid_render(int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR; |
85 | 41 | void 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 | |||
108 | enum { | ||
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 */ | ||
117 | struct 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 */ | ||
132 | struct 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 */ | ||
150 | struct 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) */ | ||
164 | static int mixing_frequency IDATA_ATTR; | ||
165 | static unsigned long freqmul IDATA_ATTR; | ||
166 | static int filtmul IDATA_ATTR; | ||
167 | #ifndef ROCKBOX | ||
168 | unsigned long attacks [16] IDATA_ATTR; | ||
169 | unsigned long releases[16] IDATA_ATTR; | ||
170 | #endif | ||
171 | |||
172 | /* ------------------------------------------------------------ globals */ | ||
173 | static struct s6581 sid IDATA_ATTR; | ||
174 | static struct sidosc osc[3] IDATA_ATTR; | ||
175 | static struct sidflt filter IDATA_ATTR; | ||
176 | |||
177 | /* ------------------------------------------------------ C64 Emu Stuff */ | ||
178 | static unsigned char bval IDATA_ATTR; | ||
179 | static unsigned short wval IDATA_ATTR; | ||
180 | /* -------------------------------------------------- Register & memory */ | ||
181 | static unsigned char a,x,y,s,p IDATA_ATTR; | ||
182 | static unsigned short pc IDATA_ATTR; | ||
183 | |||
184 | static unsigned char memory[65536]; | ||
185 | |||
186 | /* ----------------------------------------- Variables for sample stuff */ | ||
187 | static int sample_active IDATA_ATTR; | ||
188 | static int sample_position, sample_start, sample_end, sample_repeat_start IDATA_ATTR; | ||
189 | static int fracPos IDATA_ATTR; /* Fractal position of sample */ | ||
190 | static int sample_period IDATA_ATTR; | ||
191 | static int sample_repeats IDATA_ATTR; | ||
192 | static int sample_order IDATA_ATTR; | ||
193 | static int sample_nibble IDATA_ATTR; | ||
194 | |||
195 | static 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 | ||
200 | static 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 | }; | ||
207 | static 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))) | ||
215 | static 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 | }; | ||
222 | static 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 | ||
230 | static 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 | |||
250 | static 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 | |||
271 | static inline int quickfloat_ConvertFromInt(int i) | ||
272 | { | ||
273 | return (i<<16); | ||
274 | } | ||
275 | #ifndef ROCKBOX | ||
276 | static 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 | ||
283 | static inline int quickfloat_Multiply(int a, int b) | ||
284 | { | ||
285 | return (a>>8)*(b>>8); | ||
286 | } | ||
287 | static 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 */ | ||
293 | static inline unsigned char get_bit(unsigned long val, unsigned char b) | ||
294 | { | ||
295 | return (unsigned char) ((val >> b) & 1); | ||
296 | } | ||
297 | |||
298 | |||
299 | static 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 */ | ||
355 | void synth_init(unsigned long mixfrq) ICODE_ATTR; | ||
356 | void 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 */ | ||
380 | void synth_render (int32_t *buffer_r, int32_t *buffer_l, unsigned long len) ICODE_ATTR; | ||
381 | void 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 | */ | ||
586 | static inline unsigned char getmem(unsigned short addr) | ||
587 | { | ||
588 | return memory[addr]; | ||
589 | } | ||
590 | |||
591 | static 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 | */ | ||
648 | void sidPoke(int reg, unsigned char val) ICODE_ATTR; | ||
649 | void 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 | |||
694 | static 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 | |||
747 | static 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 | |||
779 | static 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 | |||
837 | static inline void setflags(int flag, int cond) | ||
838 | { | ||
839 | if (cond) p|=flag; | ||
840 | else p&=~flag; | ||
841 | } | ||
842 | |||
843 | |||
844 | static inline void push(unsigned char val) | ||
845 | { | ||
846 | setmem(0x100+s,val); | ||
847 | if (s) s--; | ||
848 | } | ||
849 | |||
850 | static inline unsigned char pop(void) | ||
851 | { | ||
852 | if (s<0xff) s++; | ||
853 | return getmem(0x100+s); | ||
854 | } | ||
855 | |||
856 | static 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 | ||
864 | void cpuReset(void) ICODE_ATTR; | 45 | for (bp = 0; bp < len; bp++) { |
865 | void 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 | |||
873 | void cpuResetTo(unsigned short npc, unsigned char na) ICODE_ATTR; | ||
874 | void 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 | |||
884 | static 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 | |||
1171 | void cpuJSR(unsigned short npc, unsigned char na) ICODE_ATTR; | ||
1172 | void 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 | |||
1188 | void c64Init(int nSampleRate) ICODE_ATTR; | ||
1189 | void c64Init(int nSampleRate) | ||
1190 | { | ||
1191 | synth_init(nSampleRate); | ||
1192 | memset(memory, 0, sizeof(memory)); | ||
1193 | |||
1194 | cpuReset(); | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | |||
1199 | unsigned 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; | ||
1201 | unsigned 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 | ||
1239 | static int nSamplesRendered = 0; | ||
1240 | static int nSamplesPerCall = 882; /* This is PAL SID single speed (44100/50Hz) */ | ||
1241 | static int nSamplesToRender = 0; | ||
1242 | |||
1243 | /* this is the codec entry point */ | ||
1244 | enum codec_status codec_main(enum codec_entry_call_reason reason) | 51 | enum 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 */ | ||
1259 | enum codec_status codec_run(void) | 63 | enum 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(¶m); | ||
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(¶m); | ||
1349 | } | 113 | } |
1350 | 114 | ||
1351 | return CODEC_OK; | 115 | return CODEC_OK; |