AudioUnit tone generator is giving me a chirp at the end of each tone generated

后端 未结 2 992
傲寒
傲寒 2021-02-04 22:48

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

2条回答
  •  悲&欢浪女
    2021-02-04 23:15

    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;
    }
    

提交回复
热议问题