Catakig/Source/LibAppleII/A2Computer/Audio.m

95 lines
2.2 KiB
Objective-C

/* class A2Computer (category Audio)
*/
#import "LibAppleII-Priv.h"
@implementation A2Computer (Audio)
//---------------------------------------------------------------------------
static struct
{
int silence; // = 0 or 128
double FIR[kFilterSize]; // partial sums of FIR coefficients
} g =
{
.silence = 128,
};
static double Sinc(double x)
{ return x? sin(x)/x : 1.; }
//---------------------------------------------------------------------------
+ (void)_InitAudio
{/*
Called once at startup, from '+initialize'. Prepares the digital filter
coefficients, and sets a default volume level.
*/
const double pi = 4. * atan(1.),
c = pi * 0.4 / kFilterRes;
double psum = 0.,
norm = 0.;
for (int j = kFilterSize; --j >= 0;)
{
int i = 2*j - kFilterSize + 1;
double h = Sinc(c * i);
// double x = i * (pi / kFilterSize);
// h *= 42 + 50*cos(x) + 8*cos(2*x); // Blackman
// h *= 54 + 46*cos(x); // Hamming
// h *= 50 + 50*cos(x); // Hann
norm += ( g.FIR[j] = h );
// NSLog(@"h[%4d] = %f", j, h);
}
for (int j = kFilterSize; --j >= 0;)
g.FIR[j] = ( psum += (g.FIR[j] / norm) );
[A2Computer SetAudioVolume:40];
}
//---------------------------------------------------------------------------
+ (void)SetAudioVolume:(unsigned)volume
{/*
Sets the volume level for audio production. Parameter 'volume' should
be between 0 and 100.
*/
if (volume > 100)
volume = 100;
A2T.audio.flat = (g.silence - volume - 1L) << 24;
long range = -256L * (2 * (int)volume + 1);
for (int i = kFilterSize; --i >= 0;)
A2T.audio.delta[i] =
((long)(g.FIR[i] * range + 0.5)) << 16;
#if 0
for (int i = LENGTH(gSpkrOut); --i >= 0;)
gSpkrOut[i] = A2T.audio.flat; //??
#endif
}
//---------------------------------------------------------------------------
- (void)_DefaultAudio:(uint8_t [])audioOut :(unsigned)nSamples
{
if (mHalts & kfHaltNoPower) // then power is off; emit hiss
{
for (int i = nSamples/4; --i >= 0;)
((uint32_t*)audioOut)[i] = 0x01010101 *
( (g.silence - 8) + (A2Random16() & 15) );
}
else // power is on, but execution still halted; emit silence
{
memset(audioOut, g.silence, nSamples);
}
}
//---------------------------------------------------------------------------
@end