summaryrefslogtreecommitdiff
path: root/apps/codecs/spc/spc_codec.h
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/spc/spc_codec.h')
-rw-r--r--apps/codecs/spc/spc_codec.h454
1 files changed, 0 insertions, 454 deletions
diff --git a/apps/codecs/spc/spc_codec.h b/apps/codecs/spc/spc_codec.h
deleted file mode 100644
index 33e566aea2..0000000000
--- a/apps/codecs/spc/spc_codec.h
+++ /dev/null
@@ -1,454 +0,0 @@
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#define NDEBUG
34#include <assert.h>
35
36/** Basic configuration options **/
37
38#define SPC_DUAL_CORE 1
39
40#if !defined(SPC_DUAL_CORE) || NUM_CORES == 1
41#undef SPC_DUAL_CORE
42#define SPC_DUAL_CORE 0
43#endif
44
45/* TGB is the only target fast enough for gaussian and realtime BRR decode */
46/* echo is almost fast enough but not quite */
47#if defined(TOSHIBA_GIGABEAT_F) || defined(TOSHIBA_GIGABEAT_S) ||\
48 defined(SIMULATOR)
49 /* Don't cache BRR waves */
50 #define SPC_BRRCACHE 0
51
52 /* Allow gaussian interpolation */
53 #define SPC_NOINTERP 0
54
55 /* Allow echo processing */
56 #define SPC_NOECHO 0
57#elif defined(CPU_COLDFIRE)
58 /* Cache BRR waves */
59 #define SPC_BRRCACHE 1
60
61 /* Disable gaussian interpolation */
62 #define SPC_NOINTERP 1
63
64 /* Allow echo processing */
65 #define SPC_NOECHO 0
66#elif defined (CPU_PP) && SPC_DUAL_CORE
67 /* Cache BRR waves */
68 #define SPC_BRRCACHE 1
69
70 /* Disable gaussian interpolation */
71 #define SPC_NOINTERP 1
72
73 /* Allow echo processing */
74 #define SPC_NOECHO 0
75#else
76 /* Cache BRR waves */
77 #define SPC_BRRCACHE 1
78
79 /* Disable gaussian interpolation */
80 #define SPC_NOINTERP 1
81
82 /* Disable echo processing */
83 #define SPC_NOECHO 1
84#endif
85
86#ifdef CPU_ARM
87
88#if CONFIG_CPU != PP5002
89 #undef ICODE_ATTR
90 #define ICODE_ATTR
91
92 #undef IDATA_ATTR
93 #define IDATA_ATTR
94
95 #undef ICONST_ATTR
96 #define ICONST_ATTR
97
98 #undef IBSS_ATTR
99 #define IBSS_ATTR
100#endif
101
102#if SPC_DUAL_CORE
103 #undef SHAREDBSS_ATTR
104 #define SHAREDBSS_ATTR __attribute__ ((section(".ibss")))
105 #undef SHAREDDATA_ATTR
106 #define SHAREDDATA_ATTR __attribute__((section(".idata")))
107#endif
108#endif
109
110/* Samples per channel per iteration */
111#if defined(CPU_PP) && NUM_CORES == 1
112#define WAV_CHUNK_SIZE 2048
113#else
114#define WAV_CHUNK_SIZE 1024
115#endif
116
117/**************** Little-endian handling ****************/
118
119static inline unsigned get_le16( void const* p )
120{
121 return ((unsigned char const*) p) [1] * 0x100u +
122 ((unsigned char const*) p) [0];
123}
124
125static inline int get_le16s( void const* p )
126{
127 return ((signed char const*) p) [1] * 0x100 +
128 ((unsigned char const*) p) [0];
129}
130
131static inline void set_le16( void* p, unsigned n )
132{
133 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
134 ((unsigned char*) p) [0] = (unsigned char) n;
135}
136
137#define GET_LE16( addr ) get_le16( addr )
138#define SET_LE16( addr, data ) set_le16( addr, data )
139#define INT16A( addr ) (*(uint16_t*) (addr))
140#define INT16SA( addr ) (*(int16_t*) (addr))
141
142#ifdef ROCKBOX_LITTLE_ENDIAN
143 #define GET_LE16A( addr ) (*(uint16_t*) (addr))
144 #define GET_LE16SA( addr ) (*( int16_t*) (addr))
145 #define SET_LE16A( addr, data ) (void) (*(uint16_t*) (addr) = (data))
146#else
147 #define GET_LE16A( addr ) get_le16 ( addr )
148 #define GET_LE16SA( addr ) get_le16s( addr )
149 #define SET_LE16A( addr, data ) set_le16 ( addr, data )
150#endif
151
152struct Spc_Emu;
153#define THIS struct Spc_Emu* const this
154
155/* The CPU portion (shock!) */
156
157struct cpu_regs_t
158{
159 long pc; /* more than 16 bits to allow overflow detection */
160 uint8_t a;
161 uint8_t x;
162 uint8_t y;
163 uint8_t status;
164 uint8_t sp;
165};
166
167struct cpu_ram_t
168{
169 union {
170 uint8_t padding1 [0x100];
171 uint16_t align;
172 } padding1 [1];
173 uint8_t ram [0x10000];
174 uint8_t padding2 [0x100];
175};
176
177#undef RAM
178#define RAM ram.ram
179extern struct cpu_ram_t ram;
180
181long CPU_run( THIS, long start_time ) ICODE_ATTR;
182void CPU_Init( THIS );
183
184/* The DSP portion (awe!) */
185enum { VOICE_COUNT = 8 };
186enum { REGISTER_COUNT = 128 };
187
188struct raw_voice_t
189{
190 int8_t volume [2];
191 uint8_t rate [2];
192 uint8_t waveform;
193 uint8_t adsr [2]; /* envelope rates for attack, decay, and sustain */
194 uint8_t gain; /* envelope gain (if not using ADSR) */
195 int8_t envx; /* current envelope level */
196 int8_t outx; /* current sample */
197 int8_t unused [6];
198};
199
200struct globals_t
201{
202 int8_t unused1 [12];
203 int8_t volume_0; /* 0C Main Volume Left (-.7) */
204 int8_t echo_feedback; /* 0D Echo Feedback (-.7) */
205 int8_t unused2 [14];
206 int8_t volume_1; /* 1C Main Volume Right (-.7) */
207 int8_t unused3 [15];
208 int8_t echo_volume_0; /* 2C Echo Volume Left (-.7) */
209 uint8_t pitch_mods; /* 2D Pitch Modulation on/off for each voice */
210 int8_t unused4 [14];
211 int8_t echo_volume_1; /* 3C Echo Volume Right (-.7) */
212 uint8_t noise_enables; /* 3D Noise output on/off for each voice */
213 int8_t unused5 [14];
214 uint8_t key_ons; /* 4C Key On for each voice */
215 uint8_t echo_ons; /* 4D Echo on/off for each voice */
216 int8_t unused6 [14];
217 uint8_t key_offs; /* 5C key off for each voice
218 (instantiates release mode) */
219 uint8_t wave_page; /* 5D source directory (wave table offsets) */
220 int8_t unused7 [14];
221 uint8_t flags; /* 6C flags and noise freq */
222 uint8_t echo_page; /* 6D */
223 int8_t unused8 [14];
224 uint8_t wave_ended; /* 7C */
225 uint8_t echo_delay; /* 7D ms >> 4 */
226 char unused9 [2];
227};
228
229enum state_t
230{ /* -1, 0, +1 allows more efficient if statements */
231 state_decay = -1,
232 state_sustain = 0,
233 state_attack = +1,
234 state_release = 2
235};
236
237struct cache_entry_t
238{
239 int16_t const* samples;
240 unsigned end; /* past-the-end position */
241 unsigned loop; /* number of samples in loop */
242 unsigned start_addr;
243};
244
245enum { BRR_BLOCK_SIZE = 16 };
246enum { BRR_CACHE_SIZE = 0x20000 + 32} ;
247
248struct voice_t
249{
250#if SPC_BRRCACHE
251 int16_t const* samples;
252 long wave_end;
253 int wave_loop;
254#else
255 int16_t samples [3 + BRR_BLOCK_SIZE + 1];
256 int block_header; /* header byte from current block */
257#endif
258 uint8_t const* addr;
259 short volume [2];
260 long position;/* position in samples buffer, with 12-bit fraction */
261 short envx;
262 short env_mode;
263 short env_timer;
264 short key_on_delay;
265};
266
267#if SPC_BRRCACHE
268/* a little extra for samples that go past end */
269extern int16_t BRRcache [BRR_CACHE_SIZE];
270#endif
271
272enum { FIR_BUF_HALF = 8 };
273
274#if defined(CPU_COLDFIRE)
275/* global because of the large aligment requirement for hardware masking -
276 * L-R interleaved 16-bit samples for easy loading and mac.w use.
277 */
278enum
279{
280 FIR_BUF_CNT = FIR_BUF_HALF,
281 FIR_BUF_SIZE = FIR_BUF_CNT * sizeof ( int32_t ),
282 FIR_BUF_ALIGN = FIR_BUF_SIZE * 2,
283 FIR_BUF_MASK = ~((FIR_BUF_ALIGN / 2) | (sizeof ( int32_t ) - 1))
284};
285#elif defined (CPU_ARM)
286enum
287{
288 FIR_BUF_CNT = FIR_BUF_HALF * 2 * 2,
289 FIR_BUF_SIZE = FIR_BUF_CNT * sizeof ( int32_t ),
290 FIR_BUF_ALIGN = FIR_BUF_SIZE,
291 FIR_BUF_MASK = ~((FIR_BUF_ALIGN / 2) | (sizeof ( int32_t ) * 2 - 1))
292};
293#endif /* CPU_* */
294
295struct Spc_Dsp
296{
297 union
298 {
299 struct raw_voice_t voice [VOICE_COUNT];
300 uint8_t reg [REGISTER_COUNT];
301 struct globals_t g;
302 int16_t align;
303 } r;
304
305 unsigned echo_pos;
306 int keys_down;
307 int noise_count;
308 uint16_t noise; /* also read as int16_t */
309
310#if defined(CPU_COLDFIRE)
311 /* circularly hardware masked address */
312 int32_t *fir_ptr;
313 /* wrapped address just behind current position -
314 allows mac.w to increment and mask fir_ptr */
315 int32_t *last_fir_ptr;
316 /* copy of echo FIR constants as int16_t for use with mac.w */
317 int16_t fir_coeff [VOICE_COUNT];
318#elif defined (CPU_ARM)
319 /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */
320 int32_t *fir_ptr;
321 /* copy of echo FIR constants as int32_t, for faster access */
322 int32_t fir_coeff [VOICE_COUNT];
323#else
324 /* fir_buf [i + 8] == fir_buf [i], to avoid wrap checking in FIR code */
325 int fir_pos; /* (0 to 7) */
326 int fir_buf [FIR_BUF_HALF * 2] [2];
327 /* copy of echo FIR constants as int, for faster access */
328 int fir_coeff [VOICE_COUNT];
329#endif
330
331 struct voice_t voice_state [VOICE_COUNT];
332
333#if SPC_BRRCACHE
334 uint8_t oldsize;
335 struct cache_entry_t wave_entry [256];
336 struct cache_entry_t wave_entry_old [256];
337#endif
338};
339
340struct src_dir
341{
342 char start [2];
343 char loop [2];
344};
345
346void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) ICODE_ATTR;
347void DSP_reset( struct Spc_Dsp* this );
348
349static inline void DSP_run( struct Spc_Dsp* this, long count, int32_t* out )
350{
351 /* Should we just fill the buffer with silence? Flags won't be cleared */
352 /* during this run so it seems it should keep resetting every sample. */
353 if ( this->r.g.flags & 0x80 )
354 DSP_reset( this );
355
356 DSP_run_( this, count, out );
357}
358
359/**************** SPC emulator ****************/
360/* 1.024 MHz clock / 32000 samples per second */
361enum { CLOCKS_PER_SAMPLE = 32 };
362
363enum { EXTRA_CLOCKS = CLOCKS_PER_SAMPLE / 2 };
364
365/* using this disables timer (since this will always be in the future) */
366enum { TIMER_DISABLED_TIME = 127 };
367
368enum { ROM_SIZE = 64 };
369enum { ROM_ADDR = 0xFFC0 };
370
371enum { TIMER_COUNT = 3 };
372
373struct Timer
374{
375 long next_tick;
376 int period;
377 int count;
378 int shift;
379 int enabled;
380 int counter;
381};
382
383void Timer_run_( struct Timer* t, long time ) ICODE_ATTR;
384
385static inline void Timer_run( struct Timer* t, long time )
386{
387 if ( time >= t->next_tick )
388 Timer_run_( t, time );
389}
390
391struct Spc_Emu
392{
393 uint8_t cycle_table [0x100];
394 struct cpu_regs_t r;
395
396 int32_t* sample_buf;
397 long next_dsp;
398 int rom_enabled;
399 int extra_cycles;
400
401 struct Timer timer [TIMER_COUNT];
402
403 /* large objects at end */
404 struct Spc_Dsp dsp;
405 uint8_t extra_ram [ROM_SIZE];
406 uint8_t boot_rom [ROM_SIZE];
407};
408
409enum { SPC_FILE_SIZE = 0x10180 };
410
411struct spc_file_t
412{
413 char signature [27];
414 char unused [10];
415 uint8_t pc [2];
416 uint8_t a;
417 uint8_t x;
418 uint8_t y;
419 uint8_t status;
420 uint8_t sp;
421 char unused2 [212];
422 uint8_t ram [0x10000];
423 uint8_t dsp [128];
424 uint8_t ipl_rom [128];
425};
426
427void SPC_Init( THIS );
428
429int SPC_load_spc( THIS, const void* data, long size );
430
431/**************** DSP interaction ****************/
432void DSP_write( struct Spc_Dsp* this, int i, int data ) ICODE_ATTR;
433
434static inline int DSP_read( struct Spc_Dsp* this, int i )
435{
436 assert( (unsigned) i < REGISTER_COUNT );
437 return this->r.reg [i];
438}
439
440void SPC_run_dsp_( THIS, long time ) ICODE_ATTR;
441
442static inline void SPC_run_dsp( THIS, long time )
443{
444 if ( time >= this->next_dsp )
445 SPC_run_dsp_( this, time );
446}
447
448int SPC_read( THIS, unsigned addr, long const time ) ICODE_ATTR;
449void SPC_write( THIS, unsigned addr, int data, long const time ) ICODE_ATTR;
450
451/**************** Sample generation ****************/
452int SPC_play( THIS, long count, int32_t* out ) ICODE_ATTR;
453
454#endif /* _SPC_CODEC_H_ */