summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/opl_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/opl_apu.c')
-rw-r--r--lib/rbcodec/codecs/libgme/opl_apu.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/opl_apu.c b/lib/rbcodec/codecs/libgme/opl_apu.c
new file mode 100644
index 0000000000..b573baef11
--- /dev/null
+++ b/lib/rbcodec/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
7blargg_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, (int)FP_ONE_VOLUME );
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
41void 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
55void 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
76static void run_until( struct Opl_Apu* this, blip_time_t end_time );
77void 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
95int 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
112void 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
121static 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}