PageRenderTime 19ms CodeModel.GetById 9ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/gme/Nes_Namco_Apu.cpp

http://game-music-emu.googlecode.com/
C++ | 145 lines | 91 code | 23 blank | 31 comment | 14 complexity | 8d327d0d6e7380313c9400887f11091d MD5 | raw file
  1// Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/
  2
  3#include "Nes_Namco_Apu.h"
  4
  5/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
  6can redistribute it and/or modify it under the terms of the GNU Lesser
  7General Public License as published by the Free Software Foundation; either
  8version 2.1 of the License, or (at your option) any later version. This
  9module is distributed in the hope that it will be useful, but WITHOUT ANY
 10WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 11FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 12details. You should have received a copy of the GNU Lesser General Public
 13License along with this module; if not, write to the Free Software Foundation,
 14Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
 15
 16#include "blargg_source.h"
 17
 18Nes_Namco_Apu::Nes_Namco_Apu()
 19{
 20	output( NULL );
 21	volume( 1.0 );
 22	reset();
 23}
 24
 25void Nes_Namco_Apu::reset()
 26{
 27	last_time = 0;
 28	addr_reg = 0;
 29	
 30	int i;
 31	for ( i = 0; i < reg_count; i++ )
 32		reg [i] = 0;
 33	
 34	for ( i = 0; i < osc_count; i++ )
 35	{
 36		Namco_Osc& osc = oscs [i];
 37		osc.delay = 0;
 38		osc.last_amp = 0;
 39		osc.wave_pos = 0;
 40	}
 41}
 42
 43void Nes_Namco_Apu::output( Blip_Buffer* buf )
 44{
 45	for ( int i = 0; i < osc_count; i++ )
 46		osc_output( i, buf );
 47}
 48
 49/*
 50void Nes_Namco_Apu::reflect_state( Tagged_Data& data )
 51{
 52	reflect_int16( data, BLARGG_4CHAR('A','D','D','R'), &addr_reg );
 53	
 54	static const char hex [17] = "0123456789ABCDEF";
 55	int i;
 56	for ( i = 0; i < reg_count; i++ )
 57		reflect_int16( data, 'RG\0\0' + hex [i >> 4] * 0x100 + hex [i & 15], &reg [i] );
 58	
 59	for ( i = 0; i < osc_count; i++ )
 60	{
 61		reflect_int32( data, BLARGG_4CHAR('D','L','Y','0') + i, &oscs [i].delay );
 62		reflect_int16( data, BLARGG_4CHAR('P','O','S','0') + i, &oscs [i].wave_pos );
 63	}
 64}
 65*/
 66
 67void Nes_Namco_Apu::end_frame( blip_time_t time )
 68{
 69	if ( time > last_time )
 70		run_until( time );
 71	
 72	assert( last_time >= time );
 73	last_time -= time;
 74}
 75
 76void Nes_Namco_Apu::run_until( blip_time_t nes_end_time )
 77{
 78	int active_oscs = (reg [0x7F] >> 4 & 7) + 1;
 79	for ( int i = osc_count - active_oscs; i < osc_count; i++ )
 80	{
 81		Namco_Osc& osc = oscs [i];
 82		Blip_Buffer* output = osc.output;
 83		if ( !output )
 84			continue;
 85		output->set_modified();
 86		
 87		blip_resampled_time_t time =
 88				output->resampled_time( last_time ) + osc.delay;
 89		blip_resampled_time_t end_time = output->resampled_time( nes_end_time );
 90		osc.delay = 0;
 91		if ( time < end_time )
 92		{
 93			const BOOST::uint8_t* osc_reg = &reg [i * 8 + 0x40];
 94			if ( !(osc_reg [4] & 0xE0) )
 95				continue;
 96			
 97			int volume = osc_reg [7] & 15;
 98			if ( !volume )
 99				continue;
100			
101			blargg_long freq = (osc_reg [4] & 3) * 0x10000 + osc_reg [2] * 0x100L + osc_reg [0];
102			if ( freq < 64 * active_oscs )
103				continue; // prevent low frequencies from excessively delaying freq changes
104			blip_resampled_time_t period =
105					output->resampled_duration( 983040 ) / freq * active_oscs;
106			
107			int wave_size = 32 - (osc_reg [4] >> 2 & 7) * 4;
108			if ( !wave_size )
109				continue;
110			
111			int last_amp = osc.last_amp;
112			int wave_pos = osc.wave_pos;
113			
114			do
115			{
116				// read wave sample
117				int addr = wave_pos + osc_reg [6];
118				int sample = reg [addr >> 1] >> (addr << 2 & 4);
119				wave_pos++;
120				sample = (sample & 15) * volume;
121				
122				// output impulse if amplitude changed
123				int delta = sample - last_amp;
124				if ( delta )
125				{
126					last_amp = sample;
127					synth.offset_resampled( time, delta, output );
128				}
129				
130				// next sample
131				time += period;
132				if ( wave_pos >= wave_size )
133					wave_pos = 0;
134			}
135			while ( time < end_time );
136			
137			osc.wave_pos = wave_pos;
138			osc.last_amp = last_amp;
139		}
140		osc.delay = time - end_time;
141	}
142	
143	last_time = nes_end_time;
144}
145