summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-07-16 21:16:52 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-07-16 21:16:52 +0000
commit84501494ceabbb05292f944721389a76cf691483 (patch)
tree4d7cc664cd272fa367cbe6f4fc9d9ed500708f02
parent8552eff9e46ede8968ea13cc172e1c61856bee18 (diff)
downloadrockbox-84501494ceabbb05292f944721389a76cf691483.tar.gz
rockbox-84501494ceabbb05292f944721389a76cf691483.zip
Forgot to add a file as usual.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13920 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/codecs/spc/spc_codec.h399
1 files changed, 399 insertions, 0 deletions
diff --git a/apps/codecs/spc/spc_codec.h b/apps/codecs/spc/spc_codec.h
new file mode 100644
index 0000000000..f2677df04a
--- /dev/null
+++ b/apps/codecs/spc/spc_codec.h
@@ -0,0 +1,399 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
11 * Copyright (C) 2004-2007 Shay Green (blargg)
12 * Copyright (C) 2002 Brad Martin
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
23/* DSP Based on Brad Martin's OpenSPC DSP emulator */
24/* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */
25
26#ifndef _SPC_CODEC_H_
27#define _SPC_CODEC_H_
28
29/* rather than comment out asserts, just define NDEBUG */
30#define NDEBUG
31#include <assert.h>
32
33/** Basic configuration options **/
34
35/* TGB is the only target fast enough for gaussian and realtime BRR decode */
36/* echo is almost fast enough but not quite */
37#ifndef TOSHIBA_GIGABEAT_F
38 /* Cache BRR waves */
39 #define SPC_BRRCACHE 1
40
41 /* Disable gaussian interpolation */
42 #define SPC_NOINTERP 1
43
44#ifndef CPU_COLDFIRE
45 /* Disable echo processing */
46 #define SPC_NOECHO 1
47#else
48 /* Enable echo processing */
49 #define SPC_NOECHO 0
50#endif
51#else
52 /* Don't cache BRR waves */
53 #define SPC_BRRCACHE 0
54
55 /* Allow gaussian interpolation */
56 #define SPC_NOINTERP 0
57
58 /* Allow echo processing */
59 #define SPC_NOECHO 0
60#endif
61
62/* Samples per channel per iteration */
63#ifdef CPU_COLDFIRE
64#define WAV_CHUNK_SIZE 1024
65#else
66#define WAV_CHUNK_SIZE 2048
67#endif
68
69#ifdef CPU_ARM
70 #undef ICODE_ATTR
71 #define ICODE_ATTR
72
73 #undef IDATA_ATTR
74 #define IDATA_ATTR
75#endif
76
77/**************** Little-endian handling ****************/
78
79static inline unsigned get_le16( void const* p )
80{
81 return ((unsigned char const*) p) [1] * 0x100u +
82 ((unsigned char const*) p) [0];
83}
84
85static inline int get_le16s( void const* p )
86{
87 return ((signed char const*) p) [1] * 0x100 +
88 ((unsigned char const*) p) [0];
89}
90
91static inline void set_le16( void* p, unsigned n )
92{
93 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
94 ((unsigned char*) p) [0] = (unsigned char) n;
95}
96
97#define GET_LE16( addr ) get_le16( addr )
98#define SET_LE16( addr, data ) set_le16( addr, data )
99#define INT16A( addr ) (*(uint16_t*) (addr))
100#define INT16SA( addr ) (*(int16_t*) (addr))
101
102#ifdef ROCKBOX_LITTLE_ENDIAN
103 #define GET_LE16A( addr ) (*(uint16_t*) (addr))
104 #define GET_LE16SA( addr ) (*( int16_t*) (addr))
105 #define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
106#else
107 #define GET_LE16A( addr ) get_le16 ( addr )
108 #define GET_LE16SA( addr ) get_le16s( addr )
109 #define SET_LE16A( addr, data ) set_le16 ( addr, data )
110#endif
111
112struct Spc_Emu;
113#define THIS struct Spc_Emu* const this
114
115/* The CPU portion (shock!) */
116
117struct cpu_regs_t
118{
119 long pc; /* more than 16 bits to allow overflow detection */
120 uint8_t a;
121 uint8_t x;
122 uint8_t y;
123 uint8_t status;
124 uint8_t sp;
125};
126
127struct cpu_ram_t
128{
129 union {
130 uint8_t padding1 [0x100];
131 uint16_t align;
132 } padding1 [1];
133 uint8_t ram [0x10000];
134 uint8_t padding2 [0x100];
135};
136
137#undef RAM
138#define RAM ram.ram
139extern struct cpu_ram_t ram;
140
141long CPU_run( THIS, long start_time ) ICODE_ATTR;
142void CPU_Init( THIS );
143
144/* The DSP portion (awe!) */
145enum { VOICE_COUNT = 8 };
146enum { REGISTER_COUNT = 128 };
147
148struct raw_voice_t
149{
150 int8_t volume [2];
151 uint8_t rate [2];
152 uint8_t waveform;
153 uint8_t adsr [2]; /* envelope rates for attack, decay, and sustain */
154 uint8_t gain; /* envelope gain (if not using ADSR) */
155 int8_t envx; /* current envelope level */
156 int8_t outx; /* current sample */
157 int8_t unused [6];
158};
159
160struct globals_t
161{
162 int8_t unused1 [12];
163 int8_t volume_0; /* 0C Main Volume Left (-.7) */
164 int8_t echo_feedback; /* 0D Echo Feedback (-.7) */
165 int8_t unused2 [14];
166 int8_t volume_1; /* 1C Main Volume Right (-.7) */
167 int8_t unused3 [15];
168 int8_t echo_volume_0; /* 2C Echo Volume Left (-.7) */
169 uint8_t pitch_mods; /* 2D Pitch Modulation on/off for each voice */
170 int8_t unused4 [14];
171 int8_t echo_volume_1; /* 3C Echo Volume Right (-.7) */
172 uint8_t noise_enables; /* 3D Noise output on/off for each voice */
173 int8_t unused5 [14];
174 uint8_t key_ons; /* 4C Key On for each voice */
175 uint8_t echo_ons; /* 4D Echo on/off for each voice */
176 int8_t unused6 [14];
177 uint8_t key_offs; /* 5C key off for each voice
178 (instantiates release mode) */
179 uint8_t wave_page; /* 5D source directory (wave table offsets) */
180 int8_t unused7 [14];
181 uint8_t flags; /* 6C flags and noise freq */
182 uint8_t echo_page; /* 6D */
183 int8_t unused8 [14];
184 uint8_t wave_ended; /* 7C */
185 uint8_t echo_delay; /* 7D ms >> 4 */
186 char unused9 [2];
187};
188
189enum state_t
190{ /* -1, 0, +1 allows more efficient if statements */
191 state_decay = -1,
192 state_sustain = 0,
193 state_attack = +1,
194 state_release = 2
195};
196
197struct cache_entry_t
198{
199 int16_t const* samples;
200 unsigned end; /* past-the-end position */
201 unsigned loop; /* number of samples in loop */
202 unsigned start_addr;
203};
204
205enum { BRR_BLOCK_SIZE = 16 };
206enum { BRR_CACHE_SIZE = 0x20000 + 32} ;
207
208struct voice_t
209{
210#if SPC_BRRCACHE
211 int16_t const* samples;
212 long wave_end;
213 int wave_loop;
214#else
215 int16_t samples [3 + BRR_BLOCK_SIZE + 1];
216 int block_header; /* header byte from current block */
217#endif
218 uint8_t const* addr;
219 short volume [2];
220 long position;/* position in samples buffer, with 12-bit fraction */
221 short envx;
222 short env_mode;
223 short env_timer;
224 short key_on_delay;
225};
226
227#if SPC_BRRCACHE
228/* a little extra for samples that go past end */
229extern int16_t BRRcache [BRR_CACHE_SIZE];
230#endif
231
232enum { FIR_BUF_HALF = 8 };
233
234#ifdef CPU_COLDFIRE
235/* global because of the large aligment requirement for hardware masking -
236 * L-R interleaved 16-bit samples for easy loading and mac.w use.
237 */
238enum
239{
240 FIR_BUF_SIZE = FIR_BUF_HALF * sizeof ( int32_t ),
241 FIR_BUF_MASK = ~FIR_BUF_SIZE
242};
243#endif /* CPU_COLDFIRE */
244
245struct Spc_Dsp
246{
247 union
248 {
249 struct raw_voice_t voice [VOICE_COUNT];
250 uint8_t reg [REGISTER_COUNT];
251 struct globals_t g;
252 int16_t align;
253 } r;
254
255 unsigned echo_pos;
256 int keys_down;
257 int noise_count;
258 uint16_t noise; /* also read as int16_t */
259
260#ifdef CPU_COLDFIRE
261 /* circularly hardware masked address */
262 int32_t *fir_ptr;
263 /* wrapped address just behind current position -
264 allows mac.w to increment and mask fir_ptr */
265 int32_t *last_fir_ptr;
266 /* copy of echo FIR constants as int16_t for use with mac.w */
267 int16_t fir_coeff[VOICE_COUNT];
268#else
269 /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */
270 int fir_pos; /* (0 to 7) */
271 int fir_buf [FIR_BUF_HALF * 2] [2];
272 /* copy of echo FIR constants as int, for faster access */
273 int fir_coeff [VOICE_COUNT];
274#endif
275
276 struct voice_t voice_state [VOICE_COUNT];
277
278#if SPC_BRRCACHE
279 uint8_t oldsize;
280 struct cache_entry_t wave_entry [256];
281 struct cache_entry_t wave_entry_old [256];
282#endif
283};
284
285struct src_dir
286{
287 char start [2];
288 char loop [2];
289};
290
291void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) ICODE_ATTR;
292void DSP_reset( struct Spc_Dsp* this );
293
294static inline void DSP_run( struct Spc_Dsp* this, long count, int32_t* out )
295{
296 /* Should we just fill the buffer with silence? Flags won't be cleared */
297 /* during this run so it seems it should keep resetting every sample. */
298 if ( this->r.g.flags & 0x80 )
299 DSP_reset( this );
300
301 DSP_run_( this, count, out );
302}
303
304/**************** SPC emulator ****************/
305/* 1.024 MHz clock / 32000 samples per second */
306enum { CLOCKS_PER_SAMPLE = 32 };
307
308enum { EXTRA_CLOCKS = CLOCKS_PER_SAMPLE / 2 };
309
310/* using this disables timer (since this will always be in the future) */
311enum { TIMER_DISABLED_TIME = 127 };
312
313enum { ROM_SIZE = 64 };
314enum { ROM_ADDR = 0xFFC0 };
315
316enum { TIMER_COUNT = 3 };
317
318struct Timer
319{
320 long next_tick;
321 int period;
322 int count;
323 int shift;
324 int enabled;
325 int counter;
326};
327
328void Timer_run_( struct Timer* t, long time ) ICODE_ATTR;
329
330static inline void Timer_run( struct Timer* t, long time )
331{
332 if ( time >= t->next_tick )
333 Timer_run_( t, time );
334}
335
336struct Spc_Emu
337{
338 uint8_t cycle_table [0x100];
339 struct cpu_regs_t r;
340
341 int32_t* sample_buf;
342 long next_dsp;
343 int rom_enabled;
344 int extra_cycles;
345
346 struct Timer timer [TIMER_COUNT];
347
348 /* large objects at end */
349 struct Spc_Dsp dsp;
350 uint8_t extra_ram [ROM_SIZE];
351 uint8_t boot_rom [ROM_SIZE];
352};
353
354enum { SPC_FILE_SIZE = 0x10180 };
355
356struct spc_file_t
357{
358 char signature [27];
359 char unused [10];
360 uint8_t pc [2];
361 uint8_t a;
362 uint8_t x;
363 uint8_t y;
364 uint8_t status;
365 uint8_t sp;
366 char unused2 [212];
367 uint8_t ram [0x10000];
368 uint8_t dsp [128];
369 uint8_t ipl_rom [128];
370};
371
372void SPC_Init( THIS );
373
374int SPC_load_spc( THIS, const void* data, long size );
375
376/**************** DSP interaction ****************/
377void DSP_write( struct Spc_Dsp* this, int i, int data ) ICODE_ATTR;
378
379static inline int DSP_read( struct Spc_Dsp* this, int i )
380{
381 assert( (unsigned) i < REGISTER_COUNT );
382 return this->r.reg [i];
383}
384
385void SPC_run_dsp_( THIS, long time ) ICODE_ATTR;
386
387static inline void SPC_run_dsp( THIS, long time )
388{
389 if ( time >= this->next_dsp )
390 SPC_run_dsp_( this, time );
391}
392
393int SPC_read( THIS, unsigned addr, long const time ) ICODE_ATTR;
394void SPC_write( THIS, unsigned addr, int data, long const time ) ICODE_ATTR;
395
396/**************** Sample generation ****************/
397int SPC_play( THIS, long count, int32_t* out ) ICODE_ATTR;
398
399#endif /* _SPC_CODEC_H_ */