diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2007-07-16 21:16:52 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2007-07-16 21:16:52 +0000 |
commit | 84501494ceabbb05292f944721389a76cf691483 (patch) | |
tree | 4d7cc664cd272fa367cbe6f4fc9d9ed500708f02 /apps/codecs | |
parent | 8552eff9e46ede8968ea13cc172e1c61856bee18 (diff) | |
download | rockbox-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
Diffstat (limited to 'apps/codecs')
-rw-r--r-- | apps/codecs/spc/spc_codec.h | 399 |
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 | |||
79 | static inline unsigned get_le16( void const* p ) | ||
80 | { | ||
81 | return ((unsigned char const*) p) [1] * 0x100u + | ||
82 | ((unsigned char const*) p) [0]; | ||
83 | } | ||
84 | |||
85 | static inline int get_le16s( void const* p ) | ||
86 | { | ||
87 | return ((signed char const*) p) [1] * 0x100 + | ||
88 | ((unsigned char const*) p) [0]; | ||
89 | } | ||
90 | |||
91 | static 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 | |||
112 | struct Spc_Emu; | ||
113 | #define THIS struct Spc_Emu* const this | ||
114 | |||
115 | /* The CPU portion (shock!) */ | ||
116 | |||
117 | struct 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 | |||
127 | struct 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 | ||
139 | extern struct cpu_ram_t ram; | ||
140 | |||
141 | long CPU_run( THIS, long start_time ) ICODE_ATTR; | ||
142 | void CPU_Init( THIS ); | ||
143 | |||
144 | /* The DSP portion (awe!) */ | ||
145 | enum { VOICE_COUNT = 8 }; | ||
146 | enum { REGISTER_COUNT = 128 }; | ||
147 | |||
148 | struct 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 | |||
160 | struct 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 | |||
189 | enum 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 | |||
197 | struct 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 | |||
205 | enum { BRR_BLOCK_SIZE = 16 }; | ||
206 | enum { BRR_CACHE_SIZE = 0x20000 + 32} ; | ||
207 | |||
208 | struct 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 */ | ||
229 | extern int16_t BRRcache [BRR_CACHE_SIZE]; | ||
230 | #endif | ||
231 | |||
232 | enum { 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 | */ | ||
238 | enum | ||
239 | { | ||
240 | FIR_BUF_SIZE = FIR_BUF_HALF * sizeof ( int32_t ), | ||
241 | FIR_BUF_MASK = ~FIR_BUF_SIZE | ||
242 | }; | ||
243 | #endif /* CPU_COLDFIRE */ | ||
244 | |||
245 | struct 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 | |||
285 | struct src_dir | ||
286 | { | ||
287 | char start [2]; | ||
288 | char loop [2]; | ||
289 | }; | ||
290 | |||
291 | void DSP_run_( struct Spc_Dsp* this, long count, int32_t* out_buf ) ICODE_ATTR; | ||
292 | void DSP_reset( struct Spc_Dsp* this ); | ||
293 | |||
294 | static 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 */ | ||
306 | enum { CLOCKS_PER_SAMPLE = 32 }; | ||
307 | |||
308 | enum { EXTRA_CLOCKS = CLOCKS_PER_SAMPLE / 2 }; | ||
309 | |||
310 | /* using this disables timer (since this will always be in the future) */ | ||
311 | enum { TIMER_DISABLED_TIME = 127 }; | ||
312 | |||
313 | enum { ROM_SIZE = 64 }; | ||
314 | enum { ROM_ADDR = 0xFFC0 }; | ||
315 | |||
316 | enum { TIMER_COUNT = 3 }; | ||
317 | |||
318 | struct Timer | ||
319 | { | ||
320 | long next_tick; | ||
321 | int period; | ||
322 | int count; | ||
323 | int shift; | ||
324 | int enabled; | ||
325 | int counter; | ||
326 | }; | ||
327 | |||
328 | void Timer_run_( struct Timer* t, long time ) ICODE_ATTR; | ||
329 | |||
330 | static inline void Timer_run( struct Timer* t, long time ) | ||
331 | { | ||
332 | if ( time >= t->next_tick ) | ||
333 | Timer_run_( t, time ); | ||
334 | } | ||
335 | |||
336 | struct 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 | |||
354 | enum { SPC_FILE_SIZE = 0x10180 }; | ||
355 | |||
356 | struct 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 | |||
372 | void SPC_Init( THIS ); | ||
373 | |||
374 | int SPC_load_spc( THIS, const void* data, long size ); | ||
375 | |||
376 | /**************** DSP interaction ****************/ | ||
377 | void DSP_write( struct Spc_Dsp* this, int i, int data ) ICODE_ATTR; | ||
378 | |||
379 | static 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 | |||
385 | void SPC_run_dsp_( THIS, long time ) ICODE_ATTR; | ||
386 | |||
387 | static inline void SPC_run_dsp( THIS, long time ) | ||
388 | { | ||
389 | if ( time >= this->next_dsp ) | ||
390 | SPC_run_dsp_( this, time ); | ||
391 | } | ||
392 | |||
393 | int SPC_read( THIS, unsigned addr, long const time ) ICODE_ATTR; | ||
394 | void SPC_write( THIS, unsigned addr, int data, long const time ) ICODE_ATTR; | ||
395 | |||
396 | /**************** Sample generation ****************/ | ||
397 | int SPC_play( THIS, long count, int32_t* out ) ICODE_ATTR; | ||
398 | |||
399 | #endif /* _SPC_CODEC_H_ */ | ||