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 }