I\'m creating a old school music emulator for the old GWBasic PLAY
command. To that end I have a tone generator and a music player. Between each of the notes played
I think that the bit where you stop audio output between notes is the culprit:
if (self.toneUnit)
{
AudioOutputUnitStop(self.toneUnit);
AudioUnitUninitialize(self.toneUnit);
AudioComponentInstanceDispose(self.toneUnit);
self.toneUnit = nil;
}
Just leave the tone unit active and you'll have less chirping. You'll need some other way to generate silence, probably by having RenderTone continue to run but generate amplitude zero.
I was able to eliminate the slight chirps that remained by having it, on a frequency change, fade the amplitude down to nothing, update the frequenmcy, and fade back in again. This is of course what the old PC speaker couldn't do (except for a few people who rapidly switched it on again), but with a very rapid fade you can probably get the old-school effect without the chirps.
Here's my fading RenderTone
function (currently using evil global variables):
double currentFrequency=0;
double currentSampleRate=0;
double currentAmplitude=0;
OSStatus RenderTone(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData)
{
// Fixed amplitude is good enough for our purposes
const double amplitude = 0.5;
// Get the tone parameters out of the view controller
ToneGen *toneGen = (__bridge ToneGen *)inRefCon;
double theta = toneGen.theta;
BOOL fadingOut = NO;
if ((currentFrequency != toneGen.frequency) || (currentSampleRate != toneGen.sampleRate))
{
if (currentAmplitude > DBL_EPSILON)
{
fadingOut = YES;
}
else
{
currentFrequency = toneGen.frequency;
currentSampleRate = toneGen.sampleRate;
}
}
double theta_increment = 2.0 * M_PI * currentFrequency /currentSampleRate;
// This is a mono tone generator so we only need the first buffer
const int channel = 0;
Float32 *buffer = (Float32 *)ioData->mBuffers[channel].mData;
// Generate the samples
for (UInt32 frame = 0; frame < inNumberFrames; frame++)
{
buffer[frame] = sin(theta) * currentAmplitude;
//NSLog(@"amplitude = %f", currentAmplitude);
theta += theta_increment;
if (theta > 2.0 * M_PI)
{
theta -= 2.0 * M_PI;
}
if (fadingOut)
{
if (currentAmplitude > 0)
{
currentAmplitude -= 0.001;
if (currentAmplitude < 0)
currentAmplitude = 0;
}
}
else
{
if (currentAmplitude < amplitude)
{
currentAmplitude += 0.001;
if (currentAmplitude > amplitude)
currentAmplitude = amplitude;
}
}
}
// Store the theta back in the view controller
toneGen.theta = theta;
return noErr;
}