summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libspc/spc_codec.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libspc/spc_codec.h')
-rw-r--r--lib/rbcodec/codecs/libspc/spc_codec.h491
1 files changed, 491 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libspc/spc_codec.h b/lib/rbcodec/codecs/libspc/spc_codec.h
new file mode 100644
index 0000000000..7f6b6e2e9f
--- /dev/null
+++ b/lib/rbcodec/codecs/libspc/spc_codec.h
@@ -0,0 +1,491 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2007-2008 Michael Sevakis (jhMikeS)
11 * Copyright (C) 2006-2007 Adam Gashlin (hcs)
12 * Copyright (C) 2004-2007 Shay Green (blargg)
13 * Copyright (C) 2002 Brad Martin
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25/* lovingly ripped off from Game_Music_Emu 0.5.2. http://www.slack.net/~ant/ */
26/* DSP Based on Brad Martin's OpenSPC DSP emulator */
27/* tag reading from sexyspc by John Brawn (John_Brawn@yahoo.com) and others */
28
29#ifndef _SPC_CODEC_H_
30#define _SPC_CODEC_H_
31
32/* rather than comment out asserts, just define NDEBUG */
33#ifndef NDEBUG
34#define NDEBUG
35#endif
36#include <assert.h>
37
38/** Basic configuration options **/
39
40#ifndef ARM_ARCH
41#define ARM_ARCH 0
42#endif
43
44#define SPC_DUAL_CORE 1
45
46#if !defined(SPC_DUAL_CORE) || NUM_CORES == 1
47#undef SPC_DUAL_CORE
48#define SPC_DUAL_CORE 0
49#endif
50
51/* Only some targets are fast enough for gaussian and realtime BRR decode */
52#if CONFIG_CPU == S3C2440 || CONFIG_CPU == IMX31L || \
53 CONFIG_CPU == AS3525 || CONFIG_CPU == AS3525v2 || \
54 defined(CPU_S5L870X) || \
55 (CONFIG_PLATFORM & PLATFORM_HOSTED) || MEMORYSIZE <= 2
56 /* Don't cache BRR waves */
57 #define SPC_BRRCACHE 0
58
59 /* Allow gaussian interpolation */
60 #define SPC_NOINTERP 0
61
62 /* Allow echo processing */
63 #define SPC_NOECHO 0
64#elif defined(CPU_COLDFIRE)
65 /* Cache BRR waves */
66 #define SPC_BRRCACHE 1
67
68 /* Disable gaussian interpolation */
69 #define SPC_NOINTERP 1
70
71 /* Allow echo processing */
72 #define SPC_NOECHO 0
73#elif defined (CPU_PP) && SPC_DUAL_CORE
74 /* Cache BRR waves */
75 #define SPC_BRRCACHE 1
76
77 /* Disable gaussian interpolation */
78 #define SPC_NOINTERP 1
79
80 /* Allow echo processing */
81 #define SPC_NOECHO 0
82#else
83 /* Cache BRR waves */
84 #define SPC_BRRCACHE 1
85
86 /* Disable gaussian interpolation */
87 #define SPC_NOINTERP 1
88
89 /* Disable echo processing */
90 #define SPC_NOECHO 1
91#endif
92
93#if (CONFIG_CPU == MCF5250)
94#define IBSS_ATTR_SPC IBSS_ATTR
95#define ICODE_ATTR_SPC ICODE_ATTR
96#define ICONST_ATTR_SPC ICONST_ATTR
97/* Not enough IRAM available to move further data to it. */
98#define IBSS_ATTR_SPC_LARGE_IRAM
99
100#elif (CONFIG_CPU == PP5020)
101/* spc is slower on PP5020 when moving data to IRAM. */
102#define IBSS_ATTR_SPC
103#define ICODE_ATTR_SPC
104#define ICONST_ATTR_SPC
105/* Not enough IRAM available to move further data to it. */
106#define IBSS_ATTR_SPC_LARGE_IRAM
107
108#elif (CONFIG_CPU == PP5022) || (CONFIG_CPU == PP5024)
109#define IBSS_ATTR_SPC IBSS_ATTR
110#define ICODE_ATTR_SPC ICODE_ATTR
111#define ICONST_ATTR_SPC ICONST_ATTR
112/* Not enough IRAM available to move further data to it. */
113#define IBSS_ATTR_SPC_LARGE_IRAM
114
115#elif defined(CPU_S5L870X)
116#define IBSS_ATTR_SPC IBSS_ATTR
117#define ICODE_ATTR_SPC ICODE_ATTR
118#define ICONST_ATTR_SPC ICONST_ATTR
119/* Very large IRAM. Move even more data to it. */
120#define IBSS_ATTR_SPC_LARGE_IRAM IBSS_ATTR
121
122#else
123#define IBSS_ATTR_SPC IBSS_ATTR
124#define ICODE_ATTR_SPC ICODE_ATTR
125#define ICONST_ATTR_SPC ICONST_ATTR
126/* Not enough IRAM available to move further data to it. */
127#define IBSS_ATTR_SPC_LARGE_IRAM
128#endif
129
130#if SPC_DUAL_CORE
131 #undef SHAREDBSS_ATTR
132 #define SHAREDBSS_ATTR __attribute__ ((section(".ibss")))
133 #undef SHAREDDATA_ATTR
134 #define SHAREDDATA_ATTR __attribute__((section(".idata")))
135#endif
136
137/* Samples per channel per iteration */
138#if defined(CPU_PP) && NUM_CORES == 1
139#define WAV_CHUNK_SIZE 2048
140#else
141#define WAV_CHUNK_SIZE 1024
142#endif
143
144/**************** Little-endian handling ****************/
145
146static inline unsigned get_le16( void const* p )
147{
148 return ((unsigned char const*) p) [1] * 0x100u +
149 ((unsigned char const*) p) [0];
150}
151
152static inline int get_le16s( void const* p )
153{
154 return ((signed char const*) p) [1] * 0x100 +
155 ((unsigned char const*) p) [0];
156}
157
158static inline void set_le16( void* p, unsigned n )
159{
160 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
161 ((unsigned char*) p) [0] = (unsigned char) n;
162}
163
164#define GET_LE16( addr ) get_le16( addr )
165#define GET_LE16A( addr ) get_le16( addr )
166#define SET_LE16( addr, data ) set_le16( addr, data )
167#define INT16A( addr ) (*(uint16_t*) (addr))
168#define INT16SA( addr ) (*(int16_t*) (addr))
169
170#ifdef ROCKBOX_LITTLE_ENDIAN
171 #define GET_LE16SA( addr ) (*( int16_t*) (addr))
172 #define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
173#else
174 #define GET_LE16SA( addr ) get_le16s( addr )
175 #define SET_LE16A( addr, data ) set_le16 ( addr, data )
176#endif
177
178struct Spc_Emu;
179#define THIS struct Spc_Emu* const this
180
181/* The CPU portion (shock!) */
182
183struct cpu_regs_t
184{
185 long pc; /* more than 16 bits to allow overflow detection */
186 uint8_t a;
187 uint8_t x;
188 uint8_t y;
189 uint8_t status;
190 uint8_t sp;
191};
192
193struct src_dir
194{
195 uint16_t start;
196 uint16_t loop;
197};
198
199struct cpu_ram_t
200{
201 union {
202 uint8_t padding1 [0x100];
203 uint16_t align;
204 } padding1 [1];
205 union {
206 uint8_t ram [0x10000];
207 struct src_dir sd [0x10000/sizeof(struct src_dir)];
208 };
209 uint8_t padding2 [0x100];
210};
211
212#undef RAM
213#define RAM ram.ram
214extern struct cpu_ram_t ram;
215
216long CPU_run( THIS, long start_time ) ICODE_ATTR_SPC;
217void CPU_Init( THIS );
218
219/* The DSP portion (awe!) */
220enum { VOICE_COUNT = 8 };
221enum { REGISTER_COUNT = 128 };
222
223struct raw_voice_t
224{
225 int8_t volume [2];
226 uint8_t rate [2];
227 uint8_t waveform;
228 uint8_t adsr [2]; /* envelope rates for attack, decay, and sustain */
229 uint8_t gain; /* envelope gain (if not using ADSR) */
230 int8_t envx; /* current envelope level */
231 int8_t outx; /* current sample */
232 int8_t unused [6];
233};
234
235struct globals_t
236{
237 int8_t unused1 [12];
238 int8_t volume_0; /* 0C Main Volume Left (-.7) */
239 int8_t echo_feedback; /* 0D Echo Feedback (-.7) */
240 int8_t unused2 [14];
241 int8_t volume_1; /* 1C Main Volume Right (-.7) */
242 int8_t unused3 [15];
243 int8_t echo_volume_0; /* 2C Echo Volume Left (-.7) */
244 uint8_t pitch_mods; /* 2D Pitch Modulation on/off for each voice */
245 int8_t unused4 [14];
246 int8_t echo_volume_1; /* 3C Echo Volume Right (-.7) */
247 uint8_t noise_enables; /* 3D Noise output on/off for each voice */
248 int8_t unused5 [14];
249 uint8_t key_ons; /* 4C Key On for each voice */
250 uint8_t echo_ons; /* 4D Echo on/off for each voice */
251 int8_t unused6 [14];
252 uint8_t key_offs; /* 5C key off for each voice
253 (instantiates release mode) */
254 uint8_t wave_page; /* 5D source directory (wave table offsets) */
255 int8_t unused7 [14];
256 uint8_t flags; /* 6C flags and noise freq */
257 uint8_t echo_page; /* 6D */
258 int8_t unused8 [14];
259 uint8_t wave_ended; /* 7C */
260 uint8_t echo_delay; /* 7D ms >> 4 */
261 char unused9 [2];
262};
263
264enum state_t
265{ /* -1, 0, +1 allows more efficient if statements */
266 state_decay = -1,
267 state_sustain = 0,
268 state_attack = +1,
269 state_release = 2
270};
271
272struct cache_entry_t
273{
274 int16_t const* samples;
275 unsigned end; /* past-the-end position */
276 unsigned loop; /* number of samples in loop */
277 unsigned start_addr;
278};
279
280enum { BRR_BLOCK_SIZE = 16 };
281enum { BRR_CACHE_SIZE = 0x20000 + 32} ;
282
283struct voice_t
284{
285#if SPC_BRRCACHE
286 int16_t const* samples;
287 long wave_end;
288 int wave_loop;
289#else
290 int16_t samples [3 + BRR_BLOCK_SIZE + 1];
291 int block_header; /* header byte from current block */
292#endif
293 uint8_t const* addr;
294 short volume [2];
295 long position;/* position in samples buffer, with 12-bit fraction */
296 short envx;
297 short env_mode;
298 short env_timer;
299 short key_on_delay;
300};
301
302#if SPC_BRRCACHE
303/* a little extra for samples that go past end */
304extern int16_t BRRcache [BRR_CACHE_SIZE];
305#endif
306
307enum { FIR_BUF_HALF = 8 };
308
309#if defined(CPU_COLDFIRE)
310/* global because of the large aligment requirement for hardware masking -
311 * L-R interleaved 16-bit samples for easy loading and mac.w use.
312 */
313enum
314{
315 FIR_BUF_CNT = FIR_BUF_HALF,
316 FIR_BUF_SIZE = FIR_BUF_CNT * sizeof ( int32_t ),
317 FIR_BUF_ALIGN = FIR_BUF_SIZE * 2,
318 FIR_BUF_MASK = ~((FIR_BUF_ALIGN / 2) | (sizeof ( int32_t ) - 1))
319};
320#elif defined (CPU_ARM)
321#if ARM_ARCH >= 6
322enum
323{
324 FIR_BUF_CNT = FIR_BUF_HALF * 2,
325 FIR_BUF_SIZE = FIR_BUF_CNT * sizeof ( int32_t ),
326 FIR_BUF_ALIGN = FIR_BUF_SIZE,
327 FIR_BUF_MASK = ~((FIR_BUF_ALIGN / 2) | (sizeof ( int32_t ) - 1))
328};
329#else
330enum
331{
332 FIR_BUF_CNT = FIR_BUF_HALF * 2 * 2,
333 FIR_BUF_SIZE = FIR_BUF_CNT * sizeof ( int32_t ),
334 FIR_BUF_ALIGN = FIR_BUF_SIZE,
335 FIR_BUF_MASK = ~((FIR_BUF_ALIGN / 2) | (sizeof ( int32_t ) * 2 - 1))
336};
337#endif /* ARM_ARCH */
338#endif /* CPU_* */
339
340struct Spc_Dsp
341{
342 union
343 {
344 struct raw_voice_t voice [VOICE_COUNT];
345 uint8_t reg [REGISTER_COUNT];
346 struct globals_t g;
347 int16_t align;
348 } r;
349
350 unsigned echo_pos;
351 int keys_down;
352 int noise_count;
353 uint16_t noise; /* also read as int16_t */
354
355#if defined(CPU_COLDFIRE)
356 /* FIR history is interleaved. Hardware handles wrapping by mask.
357 * |LR|LR|LR|LR|LR|LR|LR|LR| */
358 int32_t *fir_ptr;
359 /* wrapped address just behind current position -
360 allows mac.w to increment and mask fir_ptr */
361 int32_t *last_fir_ptr;
362 /* copy of echo FIR constants as int16_t for use with mac.w */
363 int16_t fir_coeff [VOICE_COUNT];
364#elif defined (CPU_ARM)
365 /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */
366 int32_t *fir_ptr;
367#if ARM_ARCH >= 6
368 /* FIR history is interleaved with guard to eliminate wrap checking
369 * when convolving.
370 * |LR|LR|LR|LR|LR|LR|LR|LR|--|--|--|--|--|--|--|--| */
371 /* copy of echo FIR constants as int16_t, loaded as int32 for
372 * halfword, packed multiples */
373 int16_t fir_coeff [VOICE_COUNT];
374#else
375 /* FIR history is interleaved with guard to eliminate wrap checking
376 * when convolving.
377 * |LL|RR|LL|RR|LL|RR|LL|RR|LL|RR|LL|RR|LL|RR|LL|RR|...
378 * |--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--| */
379 /* copy of echo FIR constants as int32_t, for faster access */
380 int32_t fir_coeff [VOICE_COUNT];
381#endif /* ARM_ARCH */
382#else /* Unoptimized CPU */
383 /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */
384 int fir_pos; /* (0 to 7) */
385 int fir_buf [FIR_BUF_HALF * 2] [2];
386 /* copy of echo FIR constants as int, for faster access */
387 int fir_coeff [VOICE_COUNT];
388#endif
389
390 struct voice_t voice_state [VOICE_COUNT];
391
392#if SPC_BRRCACHE
393 uint8_t oldsize;
394 struct cache_entry_t wave_entry [256];
395 struct cache_entry_t wave_entry_old [256];
396#endif
397};
398
399void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) ICODE_ATTR_SPC;
400void DSP_reset( struct Spc_Dsp* this );
401
402static inline void DSP_run( struct Spc_Dsp* this, long count, int32_t* out )
403{
404 /* Should we just fill the buffer with silence? Flags won't be cleared */
405 /* during this run so it seems it should keep resetting every sample. */
406 if ( this->r.g.flags & 0x80 )
407 DSP_reset( this );
408
409 DSP_run_( this, count, out );
410}
411
412/**************** SPC emulator ****************/
413/* 1.024 MHz clock / 32000 samples per second */
414enum { CLOCKS_PER_SAMPLE = 32 };
415
416enum { EXTRA_CLOCKS = CLOCKS_PER_SAMPLE / 2 };
417
418/* using this disables timer (since this will always be in the future) */
419enum { TIMER_DISABLED_TIME = 127 };
420
421enum { ROM_SIZE = 64 };
422enum { ROM_ADDR = 0xFFC0 };
423
424enum { TIMER_COUNT = 3 };
425
426struct Timer
427{
428 long next_tick;
429 int period;
430 int count;
431 int shift;
432 int enabled;
433 int counter;
434};
435
436struct Spc_Emu
437{
438 uint8_t cycle_table [0x100];
439 struct cpu_regs_t r;
440
441 int32_t* sample_buf;
442 long next_dsp;
443 int rom_enabled;
444 int extra_cycles;
445
446 struct Timer timer [TIMER_COUNT];
447
448 /* large objects at end */
449 struct Spc_Dsp dsp;
450 uint8_t extra_ram [ROM_SIZE];
451 uint8_t boot_rom [ROM_SIZE];
452};
453
454enum { SPC_FILE_SIZE = 0x10180 };
455
456struct spc_file_t
457{
458 char signature [27];
459 char unused [10];
460 uint8_t pc [2];
461 uint8_t a;
462 uint8_t x;
463 uint8_t y;
464 uint8_t status;
465 uint8_t sp;
466 char unused2 [212];
467 uint8_t ram [0x10000];
468 uint8_t dsp [128];
469 uint8_t ipl_rom [128];
470};
471
472void SPC_Init( THIS );
473
474int SPC_load_spc( THIS, const void* data, long size );
475
476/**************** DSP interaction ****************/
477void DSP_write( struct Spc_Dsp* this, int i, int data ) ICODE_ATTR_SPC;
478
479static inline int DSP_read( struct Spc_Dsp* this, int i )
480{
481 assert( (unsigned) i < REGISTER_COUNT );
482 return this->r.reg [i];
483}
484
485int SPC_read( THIS, unsigned addr, long const time ) ICODE_ATTR_SPC;
486void SPC_write( THIS, unsigned addr, int data, long const time ) ICODE_ATTR_SPC;
487
488/**************** Sample generation ****************/
489int SPC_play( THIS, long count, int32_t* out ) ICODE_ATTR_SPC;
490
491#endif /* _SPC_CODEC_H_ */