diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libgme/nes_fme7_apu.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libgme/nes_fme7_apu.c')
-rw-r--r-- | lib/rbcodec/codecs/libgme/nes_fme7_apu.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/nes_fme7_apu.c b/lib/rbcodec/codecs/libgme/nes_fme7_apu.c new file mode 100644 index 0000000000..3e47e0b17c --- /dev/null +++ b/lib/rbcodec/codecs/libgme/nes_fme7_apu.c | |||
@@ -0,0 +1,136 @@ | |||
1 | // Game_Music_Emu 0.5.5. http://www.slack.net/~ant/ | ||
2 | |||
3 | #include "nes_fme7_apu.h" | ||
4 | |||
5 | #include <string.h> | ||
6 | |||
7 | /* Copyright (C) 2003-2006 Shay Green. This module is free software; you | ||
8 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
9 | General Public License as published by the Free Software Foundation; either | ||
10 | version 2.1 of the License, or (at your option) any later version. This | ||
11 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
13 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
14 | details. You should have received a copy of the GNU Lesser General Public | ||
15 | License along with this module; if not, write to the Free Software Foundation, | ||
16 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
17 | |||
18 | #include "blargg_source.h" | ||
19 | |||
20 | void Fme7_init( struct Nes_Fme7_Apu* this ) | ||
21 | { | ||
22 | Synth_init( &this->synth ); | ||
23 | |||
24 | Fme7_output( this, NULL ); | ||
25 | Fme7_volume( this, (int)FP_ONE_VOLUME ); | ||
26 | Fme7_reset( this ); | ||
27 | } | ||
28 | |||
29 | void Fme7_reset( struct Nes_Fme7_Apu* this ) | ||
30 | { | ||
31 | this->last_time = 0; | ||
32 | |||
33 | int i; | ||
34 | for ( i = 0; i < fme7_osc_count; i++ ) | ||
35 | this->oscs [i].last_amp = 0; | ||
36 | |||
37 | this->latch = 0; | ||
38 | memset( this->regs, 0, sizeof this->regs); | ||
39 | memset( this->phases, 0, sizeof this->phases ); | ||
40 | memset( this->delays, 0, sizeof this->delays ); | ||
41 | } | ||
42 | |||
43 | static unsigned char const amp_table [16] = | ||
44 | { | ||
45 | #define ENTRY( n ) (unsigned char) (n * amp_range + 0.5) | ||
46 | ENTRY(0.0000), ENTRY(0.0078), ENTRY(0.0110), ENTRY(0.0156), | ||
47 | ENTRY(0.0221), ENTRY(0.0312), ENTRY(0.0441), ENTRY(0.0624), | ||
48 | ENTRY(0.0883), ENTRY(0.1249), ENTRY(0.1766), ENTRY(0.2498), | ||
49 | ENTRY(0.3534), ENTRY(0.4998), ENTRY(0.7070), ENTRY(1.0000) | ||
50 | #undef ENTRY | ||
51 | }; | ||
52 | |||
53 | void Fme7_run_until( struct Nes_Fme7_Apu* this, blip_time_t end_time ) | ||
54 | { | ||
55 | require( end_time >= this->last_time ); | ||
56 | |||
57 | int index; | ||
58 | for ( index = 0; index < fme7_osc_count; index++ ) | ||
59 | { | ||
60 | int mode = this->regs [7] >> index; | ||
61 | int vol_mode = this->regs [010 + index]; | ||
62 | int volume = amp_table [vol_mode & 0x0F]; | ||
63 | |||
64 | struct Blip_Buffer* const osc_output = this->oscs [index].output; | ||
65 | if ( !osc_output ) | ||
66 | continue; | ||
67 | |||
68 | // check for unsupported mode | ||
69 | #ifndef NDEBUG | ||
70 | if ( (mode & 011) <= 001 && vol_mode & 0x1F ) | ||
71 | debug_printf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n", | ||
72 | mode, vol_mode & 0x1F ); | ||
73 | #endif | ||
74 | |||
75 | if ( (mode & 001) | (vol_mode & 0x10) ) | ||
76 | volume = 0; // noise and envelope aren't supported | ||
77 | |||
78 | // period | ||
79 | int const period_factor = 16; | ||
80 | unsigned period = (this->regs [index * 2 + 1] & 0x0F) * 0x100 * period_factor + | ||
81 | this->regs [index * 2] * period_factor; | ||
82 | if ( period < 50 ) // around 22 kHz | ||
83 | { | ||
84 | volume = 0; | ||
85 | if ( !period ) // on my AY-3-8910A, period doesn't have extra one added | ||
86 | period = period_factor; | ||
87 | } | ||
88 | |||
89 | // current amplitude | ||
90 | int amp = volume; | ||
91 | if ( !this->phases [index] ) | ||
92 | amp = 0; | ||
93 | |||
94 | { | ||
95 | int delta = amp - this->oscs [index].last_amp; | ||
96 | if ( delta ) | ||
97 | { | ||
98 | this->oscs [index].last_amp = amp; | ||
99 | Blip_set_modified( osc_output ); | ||
100 | Synth_offset( &this->synth, this->last_time, delta, osc_output ); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | blip_time_t time = this->last_time + this->delays [index]; | ||
105 | if ( time < end_time ) | ||
106 | { | ||
107 | int delta = amp * 2 - volume; | ||
108 | Blip_set_modified( osc_output ); | ||
109 | if ( volume ) | ||
110 | { | ||
111 | do | ||
112 | { | ||
113 | delta = -delta; | ||
114 | Synth_offset_inline( &this->synth, time, delta, osc_output ); | ||
115 | time += period; | ||
116 | } | ||
117 | while ( time < end_time ); | ||
118 | |||
119 | this->oscs [index].last_amp = (delta + volume) >> 1; | ||
120 | this->phases [index] = (delta > 0); | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | // maintain phase when silent | ||
125 | int count = (end_time - time + period - 1) / period; | ||
126 | this->phases [index] ^= count & 1; | ||
127 | time += count * period; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | this->delays [index] = time - end_time; | ||
132 | } | ||
133 | |||
134 | this->last_time = end_time; | ||
135 | } | ||
136 | |||