From acb0917556fc33681c1df5a530cf754193e67705 Mon Sep 17 00:00:00 2001 From: Andree Buschmann Date: Sun, 7 Aug 2011 20:01:04 +0000 Subject: Submit initial patch from FS#12176. Adds support for several new game music formats (AY, GBS, HES, KSS, SGC, VGM and VGZ) and replaces the current NSF and NSFE with a new implementation based on a port of the Game Music Emu library 'GME'. This first submit does not cover the full functionality provided by the author's original patch: Coleco-SGV is not supported, some GME-specific m3u-support has been removed and IRAM is not used yet. Further changes are very likely to follow this submit. Thanks to Mauricio Garrido. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30264 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/libgme/opl_apu.c | 198 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 apps/codecs/libgme/opl_apu.c (limited to 'apps/codecs/libgme/opl_apu.c') 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 @@ +#include "opl_apu.h" + +#include "blargg_source.h" + +/* NOTE: Removed unused chips ~ gama */ + +blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type ) +{ + Synth_init( &this->synth ); + + this->type_ = type; + this->clock_ = clock; + this->rate_ = rate; + this->period_ = period; + Opl_set_output( this, 0 ); + Opl_volume( this, 1.0 ); + + switch (type) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + OPLL_new ( &this->opll, clock, rate ); + OPLL_reset_patch( &this->opll, OPLL_2413_TONE ); + break; + case type_vrc7: + OPLL_new ( &this->opll, clock, rate ); + OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE ); + break; + case type_msxaudio: + OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory ); + OPL_setSampleRate( &this->opl, rate, clock ); + OPL_setInternalVolume(&this->opl, 1 << 13); + break; + } + + Opl_reset( this ); + return 0; +} + +void Opl_shutdown( struct Opl_Apu* this ) +{ + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_delete( &this->opll ); + break; + case type_msxaudio: break; + } +} + +void Opl_reset( struct Opl_Apu* this ) +{ + this->addr = 0; + this->next_time = 0; + this->last_amp = 0; + + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_reset( &this->opll ); + OPLL_setMask( &this->opll, 0 ); + break; + case type_msxaudio: + OPL_reset( &this->opl ); + break; + } +} + +static void run_until( struct Opl_Apu* this, blip_time_t end_time ); +void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data ) +{ + run_until( this, time ); + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + OPLL_writeIO( &this->opll, 0, this->addr ); + OPLL_writeIO( &this->opll, 1, data ); + break; + case type_msxaudio: + OPL_writeReg( &this->opl, this->addr, data ); + break; + } +} + +int Opl_read( struct Opl_Apu* this, blip_time_t time, int port ) +{ + run_until( this, time ); + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + return OPLL_read( &this->opll, port ); + case type_msxaudio: + return OPL_readStatus( &this->opl ); + } + + return 0; +} + +void Opl_end_frame( struct Opl_Apu* this, blip_time_t time ) +{ + run_until( this, time ); + this->next_time -= time; + + if ( this->output_ ) + Blip_set_modified( this->output_ ); +} + +static void run_until( struct Opl_Apu* this, blip_time_t end_time ) +{ + if ( end_time > this->next_time ) + { + blip_time_t time_delta = end_time - this->next_time; + blip_time_t time = this->next_time; + unsigned count = time_delta / this->period_ + 1; + switch (this->type_) + { + case type_opll: + case type_msxmusic: + case type_smsfmunit: + case type_vrc7: + { + OPLL* opll = &this->opll; // cache + struct Blip_Buffer* const output = this->output_; + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + short *buffer = OPLL_update_buffer(opll, todo); + + if ( output && buffer ) + { + int last_amp = this->last_amp; + unsigned i; + for ( i = 0; i < todo; i++ ) + { + int amp = buffer [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += this->period_; + } + this->last_amp = last_amp; + } + count -= todo; + } + } + break; + case type_msxaudio: + { + struct Y8950* opl = &this->opl; + struct Blip_Buffer* const output = this->output_; + while ( count > 0 ) + { + unsigned todo = count; + if ( todo > 1024 ) todo = 1024; + int *buffer = OPL_updateBuffer(opl, todo); + + if ( output && buffer ) + { + int last_amp = this->last_amp; + unsigned i; + for ( i = 0; i < todo; i++ ) + { + int amp = buffer [i]; + int delta = amp - last_amp; + if ( delta ) + { + last_amp = amp; + Synth_offset_inline( &this->synth, time, delta, output ); + } + time += this->period_; + } + this->last_amp = last_amp; + } + count -= todo; + } + } + break; + } + this->next_time = time; + } +} -- cgit v1.2.3