Coverage Report

Created: 2026-06-09 09:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vlc/contrib/contrib-build/game-music-emu/gme/Sms_Apu.cpp
Line
Count
Source
1
// Sms_Snd_Emu 0.1.4. http://www.slack.net/~ant/
2
3
#include "Sms_Apu.h"
4
5
/* Copyright (C) 2003-2006 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
// Sms_Osc
19
20
Sms_Osc::Sms_Osc()
21
1.08k
{
22
1.08k
  output = 0;
23
1.08k
  outputs [0] = 0; // always stays NULL
24
1.08k
  outputs [1] = 0;
25
1.08k
  outputs [2] = 0;
26
1.08k
  outputs [3] = 0;
27
1.08k
}
28
29
void Sms_Osc::reset()
30
3.80k
{
31
3.80k
  delay = 0;
32
3.80k
  last_amp = 0;
33
3.80k
  volume = 0;
34
3.80k
  output_select = 3;
35
3.80k
  output = outputs [3];
36
3.80k
}
37
38
// Sms_Square
39
40
inline void Sms_Square::reset()
41
2.85k
{
42
2.85k
  period = 0;
43
2.85k
  phase = 0;
44
2.85k
  Sms_Osc::reset();
45
2.85k
}
46
47
void Sms_Square::run( blip_time_t time, blip_time_t end_time )
48
281k
{
49
281k
  if ( !volume || period <= 128 )
50
281k
  {
51
    // ignore 16kHz and higher
52
281k
    if ( last_amp )
53
0
    {
54
0
      synth->offset( time, -last_amp, output );
55
0
      last_amp = 0;
56
0
    }
57
281k
    time += delay;
58
281k
    if ( !period )
59
281k
    {
60
281k
      time = end_time;
61
281k
    }
62
25
    else if ( time < end_time )
63
25
    {
64
      // keep calculating phase
65
25
      int count = (end_time - time + period - 1) / period;
66
25
      phase = (phase + count) & 1;
67
25
      time += count * period;
68
25
    }
69
281k
  }
70
0
  else
71
0
  {
72
0
    int amp = phase ? volume : -volume;
73
0
    {
74
0
      int delta = amp - last_amp;
75
0
      if ( delta )
76
0
      {
77
0
        last_amp = amp;
78
0
        synth->offset( time, delta, output );
79
0
      }
80
0
    }
81
82
0
    time += delay;
83
0
    if ( time < end_time )
84
0
    {
85
0
      Blip_Buffer* const output = this->output;
86
0
      int delta = amp * 2;
87
0
      do
88
0
      {
89
0
        delta = -delta;
90
0
        synth->offset_inline( time, delta, output );
91
0
        time += period;
92
0
        phase ^= 1;
93
0
      }
94
0
      while ( time < end_time );
95
0
      this->last_amp = phase ? volume : -volume;
96
0
    }
97
0
  }
98
281k
  delay = time - end_time;
99
281k
}
100
101
// Sms_Noise
102
103
static int const noise_periods [3] = { 0x100, 0x200, 0x400 };
104
105
inline void Sms_Noise::reset()
106
952
{
107
952
  period = &noise_periods [0];
108
952
  shifter = 0x8000;
109
952
  feedback = 0x9000;
110
952
  Sms_Osc::reset();
111
952
}
112
113
void Sms_Noise::run( blip_time_t time, blip_time_t end_time )
114
93.8k
{
115
93.8k
  int amp = volume;
116
93.8k
  if ( shifter & 1 )
117
0
    amp = -amp;
118
119
93.8k
  {
120
93.8k
    int delta = amp - last_amp;
121
93.8k
    if ( delta )
122
0
    {
123
0
      last_amp = amp;
124
0
      synth.offset( time, delta, output );
125
0
    }
126
93.8k
  }
127
128
93.8k
  time += delay;
129
93.8k
  if ( !volume )
130
93.8k
    time = end_time;
131
132
93.8k
  if ( time < end_time )
133
0
  {
134
0
    Blip_Buffer* const output = this->output;
135
0
    unsigned shifter = this->shifter;
136
0
    int delta = amp * 2;
137
0
    int period = *this->period * 2;
138
0
    if ( !period )
139
0
      period = 16;
140
141
0
    do
142
0
    {
143
0
      int changed = shifter + 1;
144
0
      shifter = (feedback & uMinus(shifter & 1)) ^ (shifter >> 1);
145
0
      if ( changed & 2 ) // true if bits 0 and 1 differ
146
0
      {
147
0
        delta = -delta;
148
0
        synth.offset_inline( time, delta, output );
149
0
      }
150
0
      time += period;
151
0
    }
152
0
    while ( time < end_time );
153
154
0
    this->shifter = shifter;
155
0
    this->last_amp = delta >> 1;
156
0
  }
157
93.8k
  delay = time - end_time;
158
93.8k
}
159
160
// Sms_Apu
161
162
Sms_Apu::Sms_Apu()
163
271
{
164
1.08k
  for ( int i = 0; i < 3; i++ )
165
813
  {
166
813
    squares [i].synth = &square_synth;
167
813
    oscs [i] = &squares [i];
168
813
  }
169
271
  oscs [3] = &noise;
170
171
271
  volume( 1.0 );
172
271
  reset();
173
271
}
174
175
Sms_Apu::~Sms_Apu()
176
271
{
177
271
}
178
179
void Sms_Apu::volume( double vol )
180
1.09k
{
181
1.09k
  vol *= 0.85 / (osc_count * 64 * 2);
182
1.09k
  square_synth.volume( vol );
183
1.09k
  noise.synth.volume( vol );
184
1.09k
}
185
186
void Sms_Apu::treble_eq( const blip_eq_t& eq )
187
344
{
188
344
  square_synth.treble_eq( eq );
189
344
  noise.synth.treble_eq( eq );
190
344
}
191
192
void Sms_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
193
876
{
194
876
  require( (unsigned) index < osc_count );
195
876
  require( (center && left && right) || (!center && !left && !right) );
196
876
  Sms_Osc& osc = *oscs [index];
197
876
  osc.outputs [1] = right;
198
876
  osc.outputs [2] = left;
199
876
  osc.outputs [3] = center;
200
876
  osc.output = osc.outputs [osc.output_select];
201
876
}
202
203
void Sms_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
204
139
{
205
695
  for ( int i = 0; i < osc_count; i++ )
206
556
    osc_output( i, center, left, right );
207
139
}
208
209
void Sms_Apu::reset( unsigned feedback, int noise_width )
210
952
{
211
952
  last_time = 0;
212
952
  latch = 0;
213
214
952
  if ( !feedback || !noise_width )
215
944
  {
216
944
    feedback = 0x0009;
217
944
    noise_width = 16;
218
944
  }
219
  // convert to "Galios configuration"
220
952
  looped_feedback = 1 << (noise_width - 1);
221
952
  noise_feedback  = 0;
222
16.9k
  while ( noise_width-- )
223
15.9k
  {
224
15.9k
    noise_feedback = (noise_feedback << 1) | (feedback & 1);
225
15.9k
    feedback >>= 1;
226
15.9k
  }
227
228
952
  squares [0].reset();
229
952
  squares [1].reset();
230
952
  squares [2].reset();
231
952
  noise.reset();
232
952
}
233
234
void Sms_Apu::run_until( blip_time_t end_time )
235
93.9k
{
236
93.9k
  require( end_time >= last_time ); // end_time must not be before previous time
237
238
93.9k
  if ( end_time > last_time )
239
93.8k
  {
240
    // run oscillators
241
469k
    for ( int i = 0; i < osc_count; ++i )
242
375k
    {
243
375k
      Sms_Osc& osc = *oscs [i];
244
375k
      if ( osc.output )
245
375k
      {
246
375k
        osc.output->set_modified();
247
375k
        if ( i < 3 )
248
281k
          squares [i].run( last_time, end_time );
249
93.8k
        else
250
93.8k
          noise.run( last_time, end_time );
251
375k
      }
252
375k
    }
253
254
93.8k
    last_time = end_time;
255
93.8k
  }
256
93.9k
}
257
258
void Sms_Apu::end_frame( blip_time_t end_time )
259
93.9k
{
260
93.9k
  if ( end_time > last_time )
261
93.8k
    run_until( end_time );
262
263
93.9k
  assert( last_time >= end_time );
264
93.9k
  last_time -= end_time;
265
93.9k
}
266
267
void Sms_Apu::write_ggstereo( blip_time_t time, int data )
268
0
{
269
0
  require( (unsigned) data <= 0xFF );
270
271
0
  run_until( time );
272
273
0
  for ( int i = 0; i < osc_count; i++ )
274
0
  {
275
0
    Sms_Osc& osc = *oscs [i];
276
0
    int flags = data >> i;
277
0
    Blip_Buffer* old_output = osc.output;
278
0
    osc.output_select = (flags >> 3 & 2) | (flags & 1);
279
0
    osc.output = osc.outputs [osc.output_select];
280
0
    if ( osc.output != old_output && osc.last_amp )
281
0
    {
282
0
      if ( old_output )
283
0
      {
284
0
        old_output->set_modified();
285
0
        square_synth.offset( time, -osc.last_amp, old_output );
286
0
      }
287
0
      osc.last_amp = 0;
288
0
    }
289
0
  }
290
0
}
291
292
// volumes [i] = 64 * pow( 1.26, 15 - i ) / pow( 1.26, 15 )
293
static unsigned char const volumes [16] = {
294
  64, 50, 39, 31, 24, 19, 15, 12, 9, 7, 5, 4, 3, 2, 1, 0
295
};
296
297
void Sms_Apu::write_data( blip_time_t time, int data )
298
92
{
299
92
  require( (unsigned) data <= 0xFF );
300
301
92
  run_until( time );
302
303
92
  if ( data & 0x80 )
304
0
    latch = data;
305
306
92
  int index = (latch >> 5) & 3;
307
92
  if ( latch & 0x10 )
308
0
  {
309
0
    oscs [index]->volume = volumes [data & 15];
310
0
  }
311
92
  else if ( index < 3 )
312
92
  {
313
92
    Sms_Square& sq = squares [index];
314
92
    if ( data & 0x80 )
315
0
      sq.period = (sq.period & 0xFF00) | (data << 4 & 0x00FF);
316
92
    else
317
92
      sq.period = (sq.period & 0x00FF) | (data << 8 & 0x3F00);
318
92
  }
319
0
  else
320
0
  {
321
0
    int select = data & 3;
322
0
    if ( select < 3 )
323
0
      noise.period = &noise_periods [select];
324
0
    else
325
0
      noise.period = &squares [2].period;
326
327
0
    noise.feedback = (data & 0x04) ? noise_feedback : looped_feedback;
328
0
    noise.shifter = 0x8000;
329
0
  }
330
92
}