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

« back to all changes in this revision

Viewing changes to src/plugins/gme/gme/Hes_Apu.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 "Hes_Apu.h"
 
4
 
 
5
#include <string.h>
 
6
 
 
7
/* Copyright (C) 2006 Shay Green. This module is free software; you
 
8
can redistribute it and/or modify it under the terms of the GNU Lesser
 
9
General Public License as published by the Free Software Foundation; either
 
10
version 2.1 of the License, or (at your option) any later version. This
 
11
module is distributed in the hope that it will be useful, but WITHOUT ANY
 
12
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
13
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 
14
details. You should have received a copy of the GNU Lesser General Public
 
15
License along with this module; if not, write to the Free Software Foundation,
 
16
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
 
17
 
 
18
#include "blargg_source.h"
 
19
 
 
20
bool const center_waves = true; // reduces asymmetry and clamping when starting notes
 
21
 
 
22
Hes_Apu::Hes_Apu()
 
23
{
 
24
        Hes_Osc* osc = &oscs [osc_count];
 
25
        do
 
26
        {
 
27
                osc--;
 
28
                osc->outputs [0] = 0;
 
29
                osc->outputs [1] = 0;
 
30
                osc->chans [0] = 0;
 
31
                osc->chans [1] = 0;
 
32
                osc->chans [2] = 0;
 
33
        }
 
34
        while ( osc != oscs );
 
35
        
 
36
        reset();
 
37
}
 
38
 
 
39
void Hes_Apu::reset()
 
40
{
 
41
        latch   = 0;
 
42
        balance = 0xFF;
 
43
        
 
44
        Hes_Osc* osc = &oscs [osc_count];
 
45
        do
 
46
        {
 
47
                osc--;
 
48
                memset( osc, 0, offsetof (Hes_Osc,outputs) );
 
49
                osc->noise_lfsr = 1;
 
50
                osc->control    = 0x40;
 
51
                osc->balance    = 0xFF;
 
52
        }
 
53
        while ( osc != oscs );
 
54
}
 
55
 
 
56
void Hes_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
 
57
{
 
58
        require( (unsigned) index < osc_count );
 
59
        oscs [index].chans [0] = center;
 
60
        oscs [index].chans [1] = left;
 
61
        oscs [index].chans [2] = right;
 
62
        
 
63
        Hes_Osc* osc = &oscs [osc_count];
 
64
        do
 
65
        {
 
66
                osc--;
 
67
                balance_changed( *osc );
 
68
        }
 
69
        while ( osc != oscs );
 
70
}
 
71
 
 
72
void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
 
73
{
 
74
        Blip_Buffer* const osc_outputs_0 = outputs [0]; // cache often-used values
 
75
        if ( osc_outputs_0 && control & 0x80 )
 
76
        {
 
77
                int dac = this->dac;
 
78
                
 
79
                int const volume_0 = volume [0];
 
80
                {
 
81
                        int delta = dac * volume_0 - last_amp [0];
 
82
                        if ( delta )
 
83
                                synth_.offset( last_time, delta, osc_outputs_0 );
 
84
                        osc_outputs_0->set_modified();
 
85
                }
 
86
                
 
87
                Blip_Buffer* const osc_outputs_1 = outputs [1];
 
88
                int const volume_1 = volume [1];
 
89
                if ( osc_outputs_1 )
 
90
                {
 
91
                        int delta = dac * volume_1 - last_amp [1];
 
92
                        if ( delta )
 
93
                                synth_.offset( last_time, delta, osc_outputs_1 );
 
94
                        osc_outputs_1->set_modified();
 
95
                }
 
96
                
 
97
                blip_time_t time = last_time + delay;
 
98
                if ( time < end_time )
 
99
                {
 
100
                        if ( noise & 0x80 )
 
101
                        {
 
102
                                if ( volume_0 | volume_1 )
 
103
                                {
 
104
                                        // noise
 
105
                                        int const period = (32 - (noise & 0x1F)) * 64; // TODO: correct?
 
106
                                        unsigned noise_lfsr = this->noise_lfsr;
 
107
                                        do
 
108
                                        {
 
109
                                                int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
 
110
                                                // Implemented using "Galios configuration"
 
111
                                                // TODO: find correct LFSR algorithm
 
112
                                                noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1));
 
113
                                                //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
 
114
                                                int delta = new_dac - dac;
 
115
                                                if ( delta )
 
116
                                                {
 
117
                                                        dac = new_dac;
 
118
                                                        synth_.offset( time, delta * volume_0, osc_outputs_0 );
 
119
                                                        if ( osc_outputs_1 )
 
120
                                                                synth_.offset( time, delta * volume_1, osc_outputs_1 );
 
121
                                                }
 
122
                                                time += period;
 
123
                                        }
 
124
                                        while ( time < end_time );
 
125
                                        
 
126
                                        this->noise_lfsr = noise_lfsr;
 
127
                                        assert( noise_lfsr );
 
128
                                }
 
129
                        }
 
130
                        else if ( !(control & 0x40) )
 
131
                        {
 
132
                                // wave
 
133
                                int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop
 
134
                                int period = this->period * 2;
 
135
                                if ( period >= 14 && (volume_0 | volume_1) )
 
136
                                {
 
137
                                        do
 
138
                                        {
 
139
                                                int new_dac = wave [phase];
 
140
                                                phase = (phase + 1) & 0x1F;
 
141
                                                int delta = new_dac - dac;
 
142
                                                if ( delta )
 
143
                                                {
 
144
                                                        dac = new_dac;
 
145
                                                        synth_.offset( time, delta * volume_0, osc_outputs_0 );
 
146
                                                        if ( osc_outputs_1 )
 
147
                                                                synth_.offset( time, delta * volume_1, osc_outputs_1 );
 
148
                                                }
 
149
                                                time += period;
 
150
                                        }
 
151
                                        while ( time < end_time );
 
152
                                }
 
153
                                else
 
154
                                {
 
155
                                        if ( !period )
 
156
                                        {
 
157
                                                // TODO: Gekisha Boy assumes that period = 0 silences wave
 
158
                                                //period = 0x1000 * 2;
 
159
                                                period = 1;
 
160
                                                //if ( !(volume_0 | volume_1) )
 
161
                                                //  dprintf( "Used period 0\n" );
 
162
                                        }
 
163
                                        
 
164
                                        // maintain phase when silent
 
165
                                        blargg_long count = (end_time - time + period - 1) / period;
 
166
                                        phase += count; // phase will be masked below
 
167
                                        time += count * period;
 
168
                                }
 
169
                                this->phase = (phase - 1) & 0x1F; // undo pre-advance
 
170
                        }
 
171
                }
 
172
                time -= end_time;
 
173
                if ( time < 0 )
 
174
                        time = 0;
 
175
                delay = time;
 
176
                
 
177
                this->dac = dac;
 
178
                last_amp [0] = dac * volume_0;
 
179
                last_amp [1] = dac * volume_1;
 
180
        }
 
181
        last_time = end_time;
 
182
}
 
183
 
 
184
void Hes_Apu::balance_changed( Hes_Osc& osc )
 
185
{
 
186
        static short const log_table [32] = { // ~1.5 db per step
 
187
                #define ENTRY( factor ) short (factor * Hes_Osc::amp_range / 31.0 + 0.5)
 
188
                ENTRY( 0.000000 ),ENTRY( 0.005524 ),ENTRY( 0.006570 ),ENTRY( 0.007813 ),
 
189
                ENTRY( 0.009291 ),ENTRY( 0.011049 ),ENTRY( 0.013139 ),ENTRY( 0.015625 ),
 
190
                ENTRY( 0.018581 ),ENTRY( 0.022097 ),ENTRY( 0.026278 ),ENTRY( 0.031250 ),
 
191
                ENTRY( 0.037163 ),ENTRY( 0.044194 ),ENTRY( 0.052556 ),ENTRY( 0.062500 ),
 
192
                ENTRY( 0.074325 ),ENTRY( 0.088388 ),ENTRY( 0.105112 ),ENTRY( 0.125000 ),
 
193
                ENTRY( 0.148651 ),ENTRY( 0.176777 ),ENTRY( 0.210224 ),ENTRY( 0.250000 ),
 
194
                ENTRY( 0.297302 ),ENTRY( 0.353553 ),ENTRY( 0.420448 ),ENTRY( 0.500000 ),
 
195
                ENTRY( 0.594604 ),ENTRY( 0.707107 ),ENTRY( 0.840896 ),ENTRY( 1.000000 ),
 
196
                #undef ENTRY
 
197
        };
 
198
        
 
199
        int vol = (osc.control & 0x1F) - 0x1E * 2;
 
200
        
 
201
        int left  = vol + (osc.balance >> 3 & 0x1E) + (balance >> 3 & 0x1E);
 
202
        if ( left  < 0 ) left  = 0;
 
203
        
 
204
        int right = vol + (osc.balance << 1 & 0x1E) + (balance << 1 & 0x1E);
 
205
        if ( right < 0 ) right = 0;
 
206
        
 
207
        left  = log_table [left ];
 
208
        right = log_table [right];
 
209
        
 
210
        // optimizing for the common case of being centered also allows easy
 
211
        // panning using Effects_Buffer
 
212
        osc.outputs [0] = osc.chans [0]; // center
 
213
        osc.outputs [1] = 0;
 
214
        if ( left != right )
 
215
        {
 
216
                osc.outputs [0] = osc.chans [1]; // left
 
217
                osc.outputs [1] = osc.chans [2]; // right
 
218
        }
 
219
        
 
220
        if ( center_waves )
 
221
        {
 
222
                osc.last_amp [0] += (left  - osc.volume [0]) * 16;
 
223
                osc.last_amp [1] += (right - osc.volume [1]) * 16;
 
224
        }
 
225
        
 
226
        osc.volume [0] = left;
 
227
        osc.volume [1] = right;
 
228
}
 
229
 
 
230
void Hes_Apu::write_data( blip_time_t time, int addr, int data )
 
231
{
 
232
        if ( addr == 0x800 )
 
233
        {
 
234
                latch = data & 7;
 
235
        }
 
236
        else if ( addr == 0x801 )
 
237
        {
 
238
                if ( balance != data )
 
239
                {
 
240
                        balance = data;
 
241
                        
 
242
                        Hes_Osc* osc = &oscs [osc_count];
 
243
                        do
 
244
                        {
 
245
                                osc--;
 
246
                                osc->run_until( synth, time );
 
247
                                balance_changed( *oscs );
 
248
                        }
 
249
                        while ( osc != oscs );
 
250
                }
 
251
        }
 
252
        else if ( latch < osc_count )
 
253
        {
 
254
                Hes_Osc& osc = oscs [latch];
 
255
                osc.run_until( synth, time );
 
256
                switch ( addr )
 
257
                {
 
258
                case 0x802:
 
259
                        osc.period = (osc.period & 0xF00) | data;
 
260
                        break;
 
261
                
 
262
                case 0x803:
 
263
                        osc.period = (osc.period & 0x0FF) | ((data & 0x0F) << 8);
 
264
                        break;
 
265
                
 
266
                case 0x804:
 
267
                        if ( osc.control & 0x40 & ~data )
 
268
                                osc.phase = 0;
 
269
                        osc.control = data;
 
270
                        balance_changed( osc );
 
271
                        break;
 
272
                
 
273
                case 0x805:
 
274
                        osc.balance = data;
 
275
                        balance_changed( osc );
 
276
                        break;
 
277
                
 
278
                case 0x806:
 
279
                        data &= 0x1F;
 
280
                        if ( !(osc.control & 0x40) )
 
281
                        {
 
282
                                osc.wave [osc.phase] = data;
 
283
                                osc.phase = (osc.phase + 1) & 0x1F;
 
284
                        }
 
285
                        else if ( osc.control & 0x80 )
 
286
                        {
 
287
                                osc.dac = data;
 
288
                        }
 
289
                        break;
 
290
                
 
291
                 case 0x807:
 
292
                        if ( &osc >= &oscs [4] )
 
293
                                osc.noise = data;
 
294
                        break;
 
295
                 
 
296
                 case 0x809:
 
297
                        if ( !(data & 0x80) && (data & 0x03) != 0 )
 
298
                                dprintf( "HES LFO not supported\n" );
 
299
                }
 
300
        }
 
301
}
 
302
 
 
303
void Hes_Apu::end_frame( blip_time_t end_time )
 
304
{
 
305
        Hes_Osc* osc = &oscs [osc_count];
 
306
        do
 
307
        {
 
308
                osc--;
 
309
                if ( end_time > osc->last_time )
 
310
                        osc->run_until( synth, end_time );
 
311
                assert( osc->last_time >= end_time );
 
312
                osc->last_time -= end_time;
 
313
        }
 
314
        while ( osc != oscs );
 
315
}