Submit initial patch from FS#12176. Adds support for several new game music formats...
[kugel-rb.git] / apps / codecs / libgme / opl_apu.c
blobbde5e9e26eafa24ba5091fcbe5aa41acaea56414
1 #include "opl_apu.h"
3 #include "blargg_source.h"
5 /* NOTE: Removed unused chips ~ gama */
7 blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type )
9 Synth_init( &this->synth );
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 );
18 switch (type)
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;
37 Opl_reset( this );
38 return 0;
41 void Opl_shutdown( struct Opl_Apu* this )
43 switch (this->type_)
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;
55 void Opl_reset( struct Opl_Apu* this )
57 this->addr = 0;
58 this->next_time = 0;
59 this->last_amp = 0;
61 switch (this->type_)
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;
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 )
79 run_until( this, time );
80 switch (this->type_)
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;
95 int Opl_read( struct Opl_Apu* this, blip_time_t time, int port )
97 run_until( this, time );
98 switch (this->type_)
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 );
109 return 0;
112 void Opl_end_frame( struct Opl_Apu* this, blip_time_t time )
114 run_until( this, time );
115 this->next_time -= time;
117 if ( this->output_ )
118 Blip_set_modified( this->output_ );
121 static void run_until( struct Opl_Apu* this, blip_time_t end_time )
123 if ( end_time > this->next_time )
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_)
130 case type_opll:
131 case type_msxmusic:
132 case type_smsfmunit:
133 case type_vrc7:
135 OPLL* opll = &this->opll; // cache
136 struct Blip_Buffer* const output = this->output_;
137 while ( count > 0 )
139 unsigned todo = count;
140 if ( todo > 1024 ) todo = 1024;
141 short *buffer = OPLL_update_buffer(opll, todo);
143 if ( output && buffer )
145 int last_amp = this->last_amp;
146 unsigned i;
147 for ( i = 0; i < todo; i++ )
149 int amp = buffer [i];
150 int delta = amp - last_amp;
151 if ( delta )
153 last_amp = amp;
154 Synth_offset_inline( &this->synth, time, delta, output );
156 time += this->period_;
158 this->last_amp = last_amp;
160 count -= todo;
163 break;
164 case type_msxaudio:
166 struct Y8950* opl = &this->opl;
167 struct Blip_Buffer* const output = this->output_;
168 while ( count > 0 )
170 unsigned todo = count;
171 if ( todo > 1024 ) todo = 1024;
172 int *buffer = OPL_updateBuffer(opl, todo);
174 if ( output && buffer )
176 int last_amp = this->last_amp;
177 unsigned i;
178 for ( i = 0; i < todo; i++ )
180 int amp = buffer [i];
181 int delta = amp - last_amp;
182 if ( delta )
184 last_amp = amp;
185 Synth_offset_inline( &this->synth, time, delta, output );
187 time += this->period_;
189 this->last_amp = last_amp;
191 count -= todo;
194 break;
196 this->next_time = time;