~ubuntu-branches/ubuntu/wily/xmms2/wily

« back to all changes in this revision

Viewing changes to src/plugins/gme/gme/Gbs_Emu.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Benjamin Drung
  • Date: 2008-07-04 16:23:34 UTC
  • mfrom: (1.1.5 upstream) (6.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080704162334-b3esbkcapt8wbrk4
Tags: 0.5DrLecter-2ubuntu1
* Merge from debian unstable (LP: #241098), remaining changes:
  + debian/control:
    + Update Maintainer field
    + add lpia to xmms2-plugin-alsa supported architectures
    + Added liba52-0.7.4-dev to build depends
  + debian/rules: Added patch, patch-stamp and unpatch
  + changed 01_gcc4.3.patch:
    + src/include/xmmsclient/xmmsclient++/helpers.h: Added #include <climits>
* New upstream relase fixes LP: #212566, #222341

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
 
2
 
 
3
#include "Gbs_Emu.h"
 
4
 
 
5
#include "blargg_endian.h"
 
6
#include <string.h>
 
7
 
 
8
/* Copyright (C) 2003-2006 Shay Green. This module is free software; you
 
9
can redistribute it and/or modify it under the terms of the GNU Lesser
 
10
General Public License as published by the Free Software Foundation; either
 
11
version 2.1 of the License, or (at your option) any later version. This
 
12
module is distributed in the hope that it will be useful, but WITHOUT ANY
 
13
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
14
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 
15
details. You should have received a copy of the GNU Lesser General Public
 
16
License along with this module; if not, write to the Free Software Foundation,
 
17
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
 
18
 
 
19
#include "blargg_source.h"
 
20
 
 
21
Gbs_Emu::equalizer_t const Gbs_Emu::handheld_eq   = { -47.0, 2000 };
 
22
Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = {   0.0,  300 };
 
23
 
 
24
Gbs_Emu::Gbs_Emu()
 
25
{
 
26
        set_type( gme_gbs_type );
 
27
        
 
28
        static const char* const names [Gb_Apu::osc_count] = {
 
29
                "Square 1", "Square 2", "Wave", "Noise"
 
30
        };
 
31
        set_voice_names( names );
 
32
        
 
33
        static int const types [Gb_Apu::osc_count] = {
 
34
                wave_type | 1, wave_type | 2, wave_type | 0, mixed_type | 0
 
35
        };
 
36
        set_voice_types( types );
 
37
        
 
38
        set_silence_lookahead( 6 );
 
39
        set_max_initial_silence( 21 );
 
40
        set_gain( 1.2 );
 
41
        
 
42
        static equalizer_t const eq = { -1.0, 120 };
 
43
        set_equalizer( eq );
 
44
}
 
45
 
 
46
Gbs_Emu::~Gbs_Emu() { }
 
47
 
 
48
void Gbs_Emu::unload()
 
49
{
 
50
        rom.clear();
 
51
        Music_Emu::unload();
 
52
}
 
53
 
 
54
// Track info
 
55
 
 
56
static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out )
 
57
{
 
58
        GME_COPY_FIELD( h, out, game );
 
59
        GME_COPY_FIELD( h, out, author );
 
60
        GME_COPY_FIELD( h, out, copyright );
 
61
}
 
62
 
 
63
blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const
 
64
{
 
65
        copy_gbs_fields( header_, out );
 
66
        return 0;
 
67
}
 
68
 
 
69
static blargg_err_t check_gbs_header( void const* header )
 
70
{
 
71
        if ( memcmp( header, "GBS", 3 ) )
 
72
                return gme_wrong_file_type;
 
73
        return 0;
 
74
}
 
75
 
 
76
struct Gbs_File : Gme_Info_
 
77
{
 
78
        Gbs_Emu::header_t h;
 
79
        
 
80
        Gbs_File() { set_type( gme_gbs_type ); }
 
81
        
 
82
        blargg_err_t load_( Data_Reader& in )
 
83
        {
 
84
                blargg_err_t err = in.read( &h, Gbs_Emu::header_size );
 
85
                if ( err )
 
86
                        return (err == in.eof_error ? gme_wrong_file_type : err);
 
87
                
 
88
                set_track_count( h.track_count );
 
89
                return check_gbs_header( &h );
 
90
        }
 
91
        
 
92
        blargg_err_t track_info_( track_info_t* out, int ) const
 
93
        {
 
94
                copy_gbs_fields( h, out );
 
95
                return 0;
 
96
        }
 
97
};
 
98
 
 
99
static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; }
 
100
static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
 
101
 
 
102
gme_type_t_ const gme_gbs_type [1] = { "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 };
 
103
 
 
104
// Setup
 
105
 
 
106
blargg_err_t Gbs_Emu::load_( Data_Reader& in )
 
107
{
 
108
        assert( offsetof (header_t,copyright [32]) == header_size );
 
109
        RETURN_ERR( rom.load( in, header_size, &header_, 0 ) );
 
110
        
 
111
        set_track_count( header_.track_count );
 
112
        RETURN_ERR( check_gbs_header( &header_ ) );
 
113
        
 
114
        if ( header_.vers != 1 )
 
115
                set_warning( "Unknown file version" );
 
116
        
 
117
        if ( header_.timer_mode & 0x78 )
 
118
                set_warning( "Invalid timer mode" );
 
119
        
 
120
        unsigned load_addr = get_le16( header_.load_addr );
 
121
        if ( (header_.load_addr [1] | header_.init_addr [1] | header_.play_addr [1]) > 0x7F ||
 
122
                        load_addr < 0x400 )
 
123
                set_warning( "Invalid load/init/play address" );
 
124
        
 
125
        set_voice_count( Gb_Apu::osc_count );
 
126
        
 
127
        apu.volume( gain() );
 
128
        
 
129
        return setup_buffer( 4194304 );
 
130
}
 
131
 
 
132
void Gbs_Emu::update_eq( blip_eq_t const& eq )
 
133
{
 
134
        apu.treble_eq( eq );
 
135
}
 
136
 
 
137
void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
 
138
{
 
139
        apu.osc_output( i, c, l, r );
 
140
}
 
141
 
 
142
// Emulation
 
143
 
 
144
// see gb_cpu_io.h for read/write functions
 
145
 
 
146
void Gbs_Emu::set_bank( int n )
 
147
{
 
148
        blargg_long addr = rom.mask_addr( n * (blargg_long) bank_size );
 
149
        if ( addr == 0 && rom.size() > bank_size )
 
150
        {
 
151
                // TODO: what is the correct behavior? Current Game & Watch Gallery
 
152
                // rip requires that this have no effect or set to bank 1.
 
153
                //dprintf( "Selected ROM bank 0\n" );
 
154
                return;
 
155
                //n = 1;
 
156
        }
 
157
        cpu::map_code( bank_size, bank_size, rom.at_addr( addr ) );
 
158
}
 
159
 
 
160
void Gbs_Emu::update_timer()
 
161
{
 
162
        if ( header_.timer_mode & 0x04 )
 
163
        {
 
164
                static byte const rates [4] = { 10, 4, 6, 8 };
 
165
                int shift = rates [ram [hi_page + 7] & 3] - (header_.timer_mode >> 7);
 
166
                play_period = (256L - ram [hi_page + 6]) << shift;
 
167
        }
 
168
        else
 
169
        {
 
170
                play_period = 70224; // 59.73 Hz
 
171
        }
 
172
        if ( tempo() != 1.0 )
 
173
                play_period = blip_time_t (play_period / tempo());
 
174
}
 
175
 
 
176
static BOOST::uint8_t const sound_data [Gb_Apu::register_count] = {
 
177
        0x80, 0xBF, 0x00, 0x00, 0xBF, // square 1
 
178
        0x00, 0x3F, 0x00, 0x00, 0xBF, // square 2
 
179
        0x7F, 0xFF, 0x9F, 0x00, 0xBF, // wave
 
180
        0x00, 0xFF, 0x00, 0x00, 0xBF, // noise
 
181
        0x77, 0xF3, 0xF1, // vin/volume, status, power mode
 
182
        0, 0, 0, 0, 0, 0, 0, 0, 0, // unused
 
183
        0xAC, 0xDD, 0xDA, 0x48, 0x36, 0x02, 0xCF, 0x16, // waveform data
 
184
        0x2C, 0x04, 0xE5, 0x2C, 0xAC, 0xDD, 0xDA, 0x48
 
185
};
 
186
 
 
187
void Gbs_Emu::cpu_jsr( gb_addr_t addr )
 
188
{
 
189
        check( cpu::r.sp == get_le16( header_.stack_ptr ) );
 
190
        cpu::r.pc = addr;
 
191
        cpu_write( --cpu::r.sp, idle_addr >> 8 );
 
192
        cpu_write( --cpu::r.sp, idle_addr&0xFF );
 
193
}
 
194
 
 
195
void Gbs_Emu::set_tempo_( double t )
 
196
{
 
197
        apu.set_tempo( t );
 
198
        update_timer();
 
199
}
 
200
 
 
201
blargg_err_t Gbs_Emu::start_track_( int track )
 
202
{
 
203
        RETURN_ERR( Classic_Emu::start_track_( track ) );
 
204
        
 
205
        memset( ram, 0, 0x4000 );
 
206
        memset( ram + 0x4000, 0xFF, 0x1F80 );
 
207
        memset( ram + 0x5F80, 0, sizeof ram - 0x5F80 );
 
208
        ram [hi_page] = 0; // joypad reads back as 0
 
209
        
 
210
        apu.reset();
 
211
        for ( int i = 0; i < (int) sizeof sound_data; i++ )
 
212
                apu.write_register( 0, i + apu.start_addr, sound_data [i] );
 
213
        
 
214
        cpu::reset( rom.unmapped() );
 
215
        
 
216
        unsigned load_addr = get_le16( header_.load_addr );
 
217
        cpu::rst_base = load_addr;
 
218
        rom.set_addr( load_addr );
 
219
        
 
220
        cpu::map_code( ram_addr, 0x10000 - ram_addr, ram );
 
221
        cpu::map_code( 0, bank_size, rom.at_addr( 0 ) );
 
222
        set_bank( rom.size() > bank_size );
 
223
        
 
224
        ram [hi_page + 6] = header_.timer_modulo;
 
225
        ram [hi_page + 7] = header_.timer_mode;
 
226
        update_timer();
 
227
        next_play = play_period;
 
228
        
 
229
        cpu::r.a  = track;
 
230
        cpu::r.pc = idle_addr;
 
231
        cpu::r.sp = get_le16( header_.stack_ptr );
 
232
        cpu_time  = 0;
 
233
        cpu_jsr( get_le16( header_.init_addr ) );
 
234
        
 
235
        return 0;
 
236
}
 
237
 
 
238
blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int )
 
239
{
 
240
        cpu_time = 0;
 
241
        while ( cpu_time < duration )
 
242
        {
 
243
                long count = duration - cpu_time;
 
244
                cpu_time = duration;
 
245
                bool result = cpu::run( count );
 
246
                cpu_time -= cpu::remain();
 
247
                
 
248
                if ( result )
 
249
                {
 
250
                        if ( cpu::r.pc == idle_addr )
 
251
                        {
 
252
                                if ( next_play > duration )
 
253
                                {
 
254
                                        cpu_time = duration;
 
255
                                        break;
 
256
                                }
 
257
                                
 
258
                                if ( cpu_time < next_play )
 
259
                                        cpu_time = next_play;
 
260
                                next_play += play_period;
 
261
                                cpu_jsr( get_le16( header_.play_addr ) );
 
262
                                GME_FRAME_HOOK( this );
 
263
                                // TODO: handle timer rates different than 60 Hz
 
264
                        }
 
265
                        else if ( cpu::r.pc > 0xFFFF )
 
266
                        {
 
267
                                dprintf( "PC wrapped around\n" );
 
268
                                cpu::r.pc &= 0xFFFF;
 
269
                        }
 
270
                        else
 
271
                        {
 
272
                                set_warning( "Emulation error (illegal/unsupported instruction)" );
 
273
                                dprintf( "Bad opcode $%.2x at $%.4x\n",
 
274
                                                (int) *cpu::get_code( cpu::r.pc ), (int) cpu::r.pc );
 
275
                                cpu::r.pc = (cpu::r.pc + 1) & 0xFFFF;
 
276
                                cpu_time += 6;
 
277
                        }
 
278
                }
 
279
        }
 
280
        
 
281
        duration = cpu_time;
 
282
        next_play -= cpu_time;
 
283
        if ( next_play < 0 ) // could go negative if routine is taking too long to return
 
284
                next_play = 0;
 
285
        apu.end_frame( cpu_time );
 
286
        
 
287
        return 0;
 
288
}