Mercurial > audlegacy
view Plugins/Input/console/Nes_Vrc6.cpp @ 361:db298f2d3dd9 trunk
[svn] Detect files by content; remove quick detect.
author | chainsaw |
---|---|
date | Fri, 30 Dec 2005 17:56:32 -0800 |
parents | 84aabc053b6e |
children |
line wrap: on
line source
// Nes_Snd_Emu 0.1.6. http://www.slack.net/~ant/libs/ #include "Nes_Vrc6.h" #include "Tagged_Data.h" /* Copyright (C) 2003-2005 Shay Green. This module is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this module; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include BLARGG_SOURCE_BEGIN Nes_Vrc6::Nes_Vrc6() { output( NULL ); volume( 1.0 ); reset(); } void Nes_Vrc6::reset() { last_time = 0; for ( int i = 0; i < osc_count; i++ ) { Vrc6_Osc& osc = oscs [i]; for ( int j = 0; j < reg_count; j++ ) osc.regs [j] = 0; osc.delay = 0; osc.last_amp = 0; osc.phase = 1; osc.amp = 0; } } Nes_Vrc6::~Nes_Vrc6() { } void Nes_Vrc6::volume( double v ) { v *= 0.0967 * 2; saw_synth.volume( v ); square_synth.volume( v * 0.5 ); } void Nes_Vrc6::treble_eq( const blip_eq_t& eq ) { saw_synth.treble_eq( eq ); square_synth.treble_eq( eq ); } void Nes_Vrc6::output( Blip_Buffer* buf ) { for ( int i = 0; i < osc_count; i++ ) osc_output( i, buf ); } void Nes_Vrc6::run_until( nes_time_t time ) { run_square( oscs [0], time ); run_square( oscs [1], time ); run_saw( time ); last_time = time; } void Nes_Vrc6::write_osc( nes_time_t time, int osc_index, int reg, int data ) { require( (unsigned) osc_index < osc_count ); require( (unsigned) reg < reg_count ); run_until( time ); oscs [osc_index].regs [reg] = data; // to do: remove? this messed up volume envelope in Akumajou Densetsu track 22 //if ( osc_index == 2 && reg == 2 ) // oscs [2].amp = 0; } void Nes_Vrc6::end_frame( nes_time_t time ) { run_until( time ); last_time -= time; assert( last_time >= 0 ); } #define chars_to_long(s) ( (long)(s[0] << 24) | (long)(s[1] << 16) | \ (long)(s[2] << 8) | (long)(s[3]) ) void Nes_Vrc6::reflect_state( Tagged_Data& data ) { for ( int i = 0; i < osc_count; i++ ) { Tagged_Data odata( data, chars_to_long("cCH0") + i ); Vrc6_Osc& osc = oscs [i]; for ( int r = 0; r < reg_count; r++ ) reflect_int16( odata, chars_to_long("REG0") + r, &osc.regs [r] ); reflect_int16( odata, chars_to_long("DELY"), &osc.delay ); reflect_int16( odata, chars_to_long("PHAS"), &osc.phase ); if ( i == 2 ) reflect_int16( odata, chars_to_long("AMPL"), &osc.amp ); } } #include BLARGG_ENABLE_OPTIMIZER void Nes_Vrc6::run_square( Vrc6_Osc& osc, nes_time_t end_time ) { Blip_Buffer* output = osc.output; if ( !output ) return; int volume = osc.regs [0] & 15; if ( !(osc.regs [2] & 0x80) ) volume = 0; int gate = osc.regs [0] & 0x80; int duty = ((osc.regs [0] >> 4) & 7) + 1; int delta = ((gate || osc.phase < duty) ? volume : 0) - osc.last_amp; nes_time_t time = last_time; if ( delta ) { osc.last_amp += delta; square_synth.offset( time, delta, output ); } time += osc.delay; osc.delay = 0; int period = osc.period(); if ( volume && !gate && period > 4 ) { if ( time < end_time ) { int phase = osc.phase; do { phase++; if ( phase == 16 ) { phase = 0; osc.last_amp = volume; square_synth.offset( time, volume, output ); } if ( phase == duty ) { osc.last_amp = 0; square_synth.offset( time, -volume, output ); } time += period; } while ( time < end_time ); osc.phase = phase; } osc.delay = time - end_time; } } void Nes_Vrc6::run_saw( nes_time_t end_time ) { Vrc6_Osc& osc = oscs [2]; Blip_Buffer* output = osc.output; if ( !output ) return; int amp = osc.amp; int amp_step = osc.regs [0] & 0x3F; nes_time_t time = last_time; int last_amp = osc.last_amp; if ( !(osc.regs [2] & 0x80) || !(amp_step | amp) ) { osc.delay = 0; int delta = (amp >> 3) - last_amp; last_amp = amp >> 3; saw_synth.offset( time, delta, output ); } else { time += osc.delay; if ( time < end_time ) { int period = osc.period() * 2; int phase = osc.phase; do { if ( --phase == 0 ) { phase = 7; amp = 0; } int delta = (amp >> 3) - last_amp; if ( delta ) { last_amp = amp >> 3; saw_synth.offset( time, delta, output ); } time += period; amp = (amp + amp_step) & 0xFF; } while ( time < end_time ); osc.phase = phase; osc.amp = amp; } osc.delay = time - end_time; } osc.last_amp = last_amp; }