diff options
Diffstat (limited to 'apps/codecs/libgme/opl_apu.c')
-rw-r--r-- | apps/codecs/libgme/opl_apu.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/apps/codecs/libgme/opl_apu.c b/apps/codecs/libgme/opl_apu.c new file mode 100644 index 0000000000..bde5e9e26e --- /dev/null +++ b/apps/codecs/libgme/opl_apu.c | |||
@@ -0,0 +1,198 @@ | |||
1 | #include "opl_apu.h" | ||
2 | |||
3 | #include "blargg_source.h" | ||
4 | |||
5 | /* NOTE: Removed unused chips ~ gama */ | ||
6 | |||
7 | blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ) | ||
8 | { | ||
9 | Synth_init( &this->synth ); | ||
10 | |||
11 | this->type_ = type; | ||
12 | this->clock_ = clock; | ||
13 | this->rate_ = rate; | ||
14 | this->period_ = period; | ||
15 | Opl_set_output( this, 0 ); | ||
16 | Opl_volume( this, 1.0 ); | ||
17 | |||
18 | switch (type) | ||
19 | { | ||
20 | case type_opll: | ||
21 | case type_msxmusic: | ||
22 | case type_smsfmunit: | ||
23 | OPLL_new ( &this->opll, clock, rate ); | ||
24 | OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); | ||
25 | break; | ||
26 | case type_vrc7: | ||
27 | OPLL_new ( &this->opll, clock, rate ); | ||
28 | OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); | ||
29 | break; | ||
30 | case type_msxaudio: | ||
31 | OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory ); | ||
32 | OPL_setSampleRate( &this->opl, rate, clock ); | ||
33 | OPL_setInternalVolume(&this->opl, 1 << 13); | ||
34 | break; | ||
35 | } | ||
36 | |||
37 | Opl_reset( this ); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | void Opl_shutdown( struct Opl_Apu* this ) | ||
42 | { | ||
43 | switch (this->type_) | ||
44 | { | ||
45 | case type_opll: | ||
46 | case type_msxmusic: | ||
47 | case type_smsfmunit: | ||
48 | case type_vrc7: | ||
49 | OPLL_delete( &this->opll ); | ||
50 | break; | ||
51 | case type_msxaudio: break; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | void Opl_reset( struct Opl_Apu* this ) | ||
56 | { | ||
57 | this->addr = 0; | ||
58 | this->next_time = 0; | ||
59 | this->last_amp = 0; | ||
60 | |||
61 | switch (this->type_) | ||
62 | { | ||
63 | case type_opll: | ||
64 | case type_msxmusic: | ||
65 | case type_smsfmunit: | ||
66 | case type_vrc7: | ||
67 | OPLL_reset( &this->opll ); | ||
68 | OPLL_setMask( &this->opll, 0 ); | ||
69 | break; | ||
70 | case type_msxaudio: | ||
71 | OPL_reset( &this->opl ); | ||
72 | break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | static void run_until( struct Opl_Apu* this, blip_time_t end_time ); | ||
77 | void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data ) | ||
78 | { | ||
79 | run_until( this, time ); | ||
80 | switch (this->type_) | ||
81 | { | ||
82 | case type_opll: | ||
83 | case type_msxmusic: | ||
84 | case type_smsfmunit: | ||
85 | case type_vrc7: | ||
86 | OPLL_writeIO( &this->opll, 0, this->addr ); | ||
87 | OPLL_writeIO( &this->opll, 1, data ); | ||
88 | break; | ||
89 | case type_msxaudio: | ||
90 | OPL_writeReg( &this->opl, this->addr, data ); | ||
91 | break; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | int Opl_read( struct Opl_Apu* this, blip_time_t time, int port ) | ||
96 | { | ||
97 | run_until( this, time ); | ||
98 | switch (this->type_) | ||
99 | { | ||
100 | case type_opll: | ||
101 | case type_msxmusic: | ||
102 | case type_smsfmunit: | ||
103 | case type_vrc7: | ||
104 | return OPLL_read( &this->opll, port ); | ||
105 | case type_msxaudio: | ||
106 | return OPL_readStatus( &this->opl ); | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | void Opl_end_frame( struct Opl_Apu* this, blip_time_t time ) | ||
113 | { | ||
114 | run_until( this, time ); | ||
115 | this->next_time -= time; | ||
116 | |||
117 | if ( this->output_ ) | ||
118 | Blip_set_modified( this->output_ ); | ||
119 | } | ||
120 | |||
121 | static void run_until( struct Opl_Apu* this, blip_time_t end_time ) | ||
122 | { | ||
123 | if ( end_time > this->next_time ) | ||
124 | { | ||
125 | blip_time_t time_delta = end_time - this->next_time; | ||
126 | blip_time_t time = this->next_time; | ||
127 | unsigned count = time_delta / this->period_ + 1; | ||
128 | switch (this->type_) | ||
129 | { | ||
130 | case type_opll: | ||
131 | case type_msxmusic: | ||
132 | case type_smsfmunit: | ||
133 | case type_vrc7: | ||
134 | { | ||
135 | OPLL* opll = &this->opll; // cache | ||
136 | struct Blip_Buffer* const output = this->output_; | ||
137 | while ( count > 0 ) | ||
138 | { | ||
139 | unsigned todo = count; | ||
140 | if ( todo > 1024 ) todo = 1024; | ||
141 | short *buffer = OPLL_update_buffer(opll, todo); | ||
142 | |||
143 | if ( output && buffer ) | ||
144 | { | ||
145 | int last_amp = this->last_amp; | ||
146 | unsigned i; | ||
147 | for ( i = 0; i < todo; i++ ) | ||
148 | { | ||
149 | int amp = buffer [i]; | ||
150 | int delta = amp - last_amp; | ||
151 | if ( delta ) | ||
152 | { | ||
153 | last_amp = amp; | ||
154 | Synth_offset_inline( &this->synth, time, delta, output ); | ||
155 | } | ||
156 | time += this->period_; | ||
157 | } | ||
158 | this->last_amp = last_amp; | ||
159 | } | ||
160 | count -= todo; | ||
161 | } | ||
162 | } | ||
163 | break; | ||
164 | case type_msxaudio: | ||
165 | { | ||
166 | struct Y8950* opl = &this->opl; | ||
167 | struct Blip_Buffer* const output = this->output_; | ||
168 | while ( count > 0 ) | ||
169 | { | ||
170 | unsigned todo = count; | ||
171 | if ( todo > 1024 ) todo = 1024; | ||
172 | int *buffer = OPL_updateBuffer(opl, todo); | ||
173 | |||
174 | if ( output && buffer ) | ||
175 | { | ||
176 | int last_amp = this->last_amp; | ||
177 | unsigned i; | ||
178 | for ( i = 0; i < todo; i++ ) | ||
179 | { | ||
180 | int amp = buffer [i]; | ||
181 | int delta = amp - last_amp; | ||
182 | if ( delta ) | ||
183 | { | ||
184 | last_amp = amp; | ||
185 | Synth_offset_inline( &this->synth, time, delta, output ); | ||
186 | } | ||
187 | time += this->period_; | ||
188 | } | ||
189 | this->last_amp = last_amp; | ||
190 | } | ||
191 | count -= todo; | ||
192 | } | ||
193 | } | ||
194 | break; | ||
195 | } | ||
196 | this->next_time = time; | ||
197 | } | ||
198 | } | ||