Mercurial > audlegacy-plugins
view src/console/Track_Emu.cxx @ 1062:1d65dcdb714c trunk
[svn] - bump version of plugins and version requirements per plugin api v2
author | nenolod |
---|---|
date | Thu, 24 May 2007 02:12:43 -0700 |
parents | 3da1b8942b8b |
children |
line wrap: on
line source
// Game_Music_Emu 0.3.0. http://www.slack.net/~ant/ #include "Track_Emu.h" #include <string.h> #include <math.h> /* Copyright (C) 2005-2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include BLARGG_SOURCE_BEGIN int const stereo = 2; // channels for a stereo signal int const fade_block_size = 512; int const fade_length = 8000; // msec int const silence_max = 6; // seconds int const silence_threshold = 0x10; long Track_Emu::msec_to_samples( long msec ) const { long rate = emu->sample_rate() * stereo; return (msec / 1000L) * rate + (msec % 1000L) * rate / 1000; } void Track_Emu::sync( long time ) { buf_count = 0; silence_count = 0; emu_time = time; out_time = time; silence_time = time; track_ended = time > fade_time + fade_length * stereo * emu->sample_rate(); } void Track_Emu::restart_track() { emu->start_track( track ); sync ( 0 ); // skip initial silence for ( int n = 40 * stereo * emu->sample_rate() / buf_size; n--; ) { fill_buf( true ); if ( buf_count || track_ended ) break; } sync( 0 ); } void Track_Emu::seek( long time ) { long pos = msec_to_samples( time ) & ~1; if ( pos < out_time ) restart_track(); emu->skip( pos - emu_time ); sync( pos ); } long Track_Emu::tell() const { long rate = emu->sample_rate() * stereo; return (out_time / rate * 1000) + (out_time % rate * 1000 / rate); } void Track_Emu::start_track( Music_Emu* e, int t, long length, bool ds ) { // to do: remove //length = 50 * 1000; //ds = true; //t = 23; emu = e; track = t; detect_silence = ds; fade_factor = pow( 0.005, 1.0 / msec_to_samples( fade_length ) ); fade_time = msec_to_samples( length ); restart_track(); } static bool is_silence( const Music_Emu::sample_t* p, int count ) { while ( count-- ) { if ( (unsigned) (*p++ + silence_threshold / 2) > (unsigned) silence_threshold ) return false; } return true; } void Track_Emu::fill_buf( bool check_silence ) { emu->play( buf_size, buf ); emu_time += buf_size; if ( (check_silence || emu_time > fade_time) && is_silence( buf, buf_size ) ) { silence_count += buf_size; } else { silence_time = emu_time; buf_count = buf_size; } if ( emu->track_ended() || emu->error_count() ) track_ended = true; } inline void Track_Emu::end_track() { silence_count = 0; buf_count = 0; track_ended = true; } bool Track_Emu::play( int out_count, Music_Emu::sample_t* out ) { assert( out_count % 2 == 0 ); assert( emu ); int pos = 0; while ( pos < out_count ) { // fill with any remaining silence int count = min( silence_count, out_count - pos ); if ( count ) { silence_count -= count; memset( &out [pos], 0, count * sizeof *out ); } else { // empty internal buffer count = min( buf_count, out_count - pos ); if ( !count && track_ended ) { memset( &out [pos], 0, (out_count - pos) * sizeof *out ); return true; } memcpy( &out [pos], &buf [buf_size - buf_count], count * sizeof *out ); buf_count -= count; } pos += count; // keep internal buffer full and possibly run ahead for ( int n = 6; n--; ) { if ( buf_count || track_ended || emu_time - out_time > silence_max * stereo * emu->sample_rate() ) break; fill_buf( detect_silence ); } } out_time += out_count; if ( detect_silence && ( emu_time - silence_time > silence_max * stereo * emu->sample_rate() && silence_time ) ) end_track(); // fade if track is ending if ( out_time > fade_time ) { for ( int i = 0; i < out_count; i += fade_block_size ) { double gain = pow( fade_factor, (double) (out_time + i - fade_time) ); if ( gain < 0.005 ) end_track(); int count = min( fade_block_size, out_count - i ); int igain = (unsigned int)((double)gain * (1 << 15));; for ( int j = 0; j < count; j++ ) out [i + j] = (out [i + j] * igain) >> 15; } } return !silence_count && !buf_count && track_ended; }