1 // Game_Music_Emu $vers. http://www.slack.net/~ant/
2 
3 #include "Gbs_Emu.h"
4 
5 /* Copyright (C) 2003-2009 Shay Green. This module is free software; you
6 can redistribute it and/or modify it under the terms of the GNU Lesser
7 General Public License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version. This
9 module is distributed in the hope that it will be useful, but WITHOUT ANY
10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 details. You should have received a copy of the GNU Lesser General Public
13 License along with this module; if not, write to the Free Software Foundation,
14 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "blargg_source.h"
17 
18 Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq   = { -47.0, 2000, 0,0,0,0,0,0,0,0 };
19 Gbs_Emu::equalizer_t const Gbs_Emu::cgb_eq        = {   0.0,  300, 0,0,0,0,0,0,0,0 };
20 Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = {   0.0,   30, 0,0,0,0,0,0,0,0 }; // DMG
21 
Gbs_Emu()22 Gbs_Emu::Gbs_Emu()
23 {
24 	sound_hardware = sound_gbs;
25 	enable_clicking( false );
26 	set_type( gme_gbs_type );
27 	set_silence_lookahead( 6 );
28 	set_max_initial_silence( 21 );
29 	set_gain( 1.2 );
30 
31 	// kind of midway between headphones and speaker
32 	static equalizer_t const eq = { -1.0, 120, 0,0,0,0,0,0,0,0 };
33 	set_equalizer( eq );
34 }
35 
~Gbs_Emu()36 Gbs_Emu::~Gbs_Emu() { }
37 
unload()38 void Gbs_Emu::unload()
39 {
40 	core_.unload();
41 	Music_Emu::unload();
42 }
43 
44 // Track info
45 
copy_gbs_fields(Gbs_Emu::header_t const & h,track_info_t * out)46 static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out )
47 {
48 	GME_COPY_FIELD( h, out, game );
49 	GME_COPY_FIELD( h, out, author );
50 	GME_COPY_FIELD( h, out, copyright );
51 }
52 
hash_gbs_file(Gbs_Emu::header_t const & h,byte const * data,int data_size,Music_Emu::Hash_Function & out)53 static void hash_gbs_file( Gbs_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out )
54 {
55 	out.hash_( &h.vers, sizeof(h.vers) );
56 	out.hash_( &h.track_count, sizeof(h.track_count) );
57 	out.hash_( &h.first_track, sizeof(h.first_track) );
58 	out.hash_( &h.load_addr[0], sizeof(h.load_addr) );
59 	out.hash_( &h.init_addr[0], sizeof(h.init_addr) );
60 	out.hash_( &h.play_addr[0], sizeof(h.play_addr) );
61 	out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) );
62 	out.hash_( &h.timer_modulo, sizeof(h.timer_modulo) );
63 	out.hash_( &h.timer_mode, sizeof(h.timer_mode) );
64 	out.hash_( data, data_size );
65 }
66 
track_info_(track_info_t * out,int) const67 blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const
68 {
69 	copy_gbs_fields( header(), out );
70 	return blargg_ok;
71 }
72 
73 struct Gbs_File : Gme_Info_
74 {
75 	Gbs_Emu::header_t const* h;
76 
Gbs_FileGbs_File77 	Gbs_File() { set_type( gme_gbs_type ); }
78 
load_mem_Gbs_File79 	blargg_err_t load_mem_( byte const begin [], int size )
80 	{
81 		h = ( Gbs_Emu::header_t * ) begin;
82 
83 		set_track_count( h->track_count );
84 		if ( !h->valid_tag() )
85 			return blargg_err_file_type;
86 
87 		return blargg_ok;
88 	}
89 
track_info_Gbs_File90 	blargg_err_t track_info_( track_info_t* out, int ) const
91 	{
92 		copy_gbs_fields( Gbs_Emu::header_t( *h ), out );
93 		return blargg_ok;
94 	}
95 
hash_Gbs_File96 	blargg_err_t hash_( Hash_Function& out ) const
97 	{
98 		hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out );
99 		return blargg_ok;
100 	}
101 };
102 
new_gbs_emu()103 static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; }
new_gbs_file()104 static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
105 
106 gme_type_t_ const gme_gbs_type [1] = {{ "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }};
107 
108 // Setup
109 
load_(Data_Reader & in)110 blargg_err_t Gbs_Emu::load_( Data_Reader& in )
111 {
112 	RETURN_ERR( core_.load( in ) );
113 	set_warning( core_.warning() );
114 	set_track_count( header().track_count );
115 	set_voice_count( Gb_Apu::osc_count );
116 	core_.apu().volume( gain() );
117 
118 	static const char* const names [Gb_Apu::osc_count] = {
119 		"Square 1", "Square 2", "Wave", "Noise"
120 	};
121 	set_voice_names( names );
122 
123 	static int const types [Gb_Apu::osc_count] = {
124 		wave_type+1, wave_type+2, wave_type+3, mixed_type+1
125 	};
126 	set_voice_types( types );
127 
128 	return setup_buffer( 4194304 );
129 }
130 
update_eq(blip_eq_t const & eq)131 void Gbs_Emu::update_eq( blip_eq_t const& eq )
132 {
133 	core_.apu().treble_eq( eq );
134 }
135 
set_voice(int i,Blip_Buffer * c,Blip_Buffer * l,Blip_Buffer * r)136 void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
137 {
138 	core_.apu().set_output( i, c, l, r );
139 }
140 
set_tempo_(double t)141 void Gbs_Emu::set_tempo_( double t )
142 {
143 	core_.set_tempo( t );
144 }
145 
start_track_(int track)146 blargg_err_t Gbs_Emu::start_track_( int track )
147 {
148 	sound_t mode = sound_hardware;
149 	if ( mode == sound_gbs )
150 		mode = (header().timer_mode & 0x80) ? sound_cgb : sound_dmg;
151 
152 	RETURN_ERR( core_.start_track( track, (Gb_Apu::mode_t) mode ) );
153 
154 	// clear buffer AFTER track is started, eliminating initial click
155 	return Classic_Emu::start_track_( track );
156 }
157 
run_clocks(blip_time_t & duration,int)158 blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int )
159 {
160 	return core_.end_frame( duration );
161 }
162 
hash_(Hash_Function & out) const163 blargg_err_t Gbs_Emu::hash_( Hash_Function& out ) const
164 {
165 	hash_gbs_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out );
166 	return blargg_ok;
167 }