CoreAudio: AudioUnit can neither be stopped nor uninitialized - core-audio

I wrote a command line c tool generating an sine wave and playing it using CoreAudio on the default audio output. I am initializing a
AURenderCallbackStruct and initialize an AudioUnit using AudioUnitInitialize (as already discussed in this forum). All this is working as intended, but when it comes to closing the program I am not able to close the AudioUnit, neither with using AudioOutputUnitStop(player.outputUnit); nor AudioOutputUnitStop(player.outputUnit); nor
AudioComponentInstanceDispose(player.outputUnit);
The order of appearance of these calls in the code does not change the behavior.
The program is compiled without error messages, but the sine is still audible as long as the rest of the program is running.
Here is the code I'm using for initializing the AudioUnit:
void CreateAndConnectOutputUnit (ToneGenerator *player) {
AudioComponentDescription outputcd = {0};
outputcd.componentType = kAudioUnitType_Output;
outputcd.componentSubType = kAudioUnitSubType_DefaultOutput;
outputcd.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext (NULL, &outputcd);
if (comp == NULL) {
printf ("can't get output unit");
exit (-1);
}
AudioComponentInstanceNew(comp, &player->outputUnit);
// register render callback
AURenderCallbackStruct input;
input.inputProc = SineWaveRenderCallback;
input.inputProcRefCon = player;
AudioUnitSetProperty(player->outputUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Output,
0,
&input,
sizeof(input);
// initialize unit
AudioUnitInitialize(player->outputUnit);
}
In my main program I'm starting the AudioUnit and the sine wave.
void main {
// code for doing various things
ToneGenerator player = {0}; // create a sound object
CreateAndConnectOutputUnit (&player);
AudioOutputUnitStart(player.outputUnit);
// waiting to listen to the sine wave
sleep(3);
// attempt to stop the sound output
AudioComponentInstanceDispose(player.outputUnit);
AudioUnitUninitialize(player.outputUnit);
AudioOutputUnitStop(player.outputUnit);
//additional code that should be executed without sine wave being audible
}
As I'm new to both, this forum as well as programming in Xcode I hope that I could explain this issue in a way that you can help me out and I hope that I didn't miss the answer somewhere in the forum while searching for a solution.
Thank you in advance for your time and input,
Stefan

You should manage and unmanage your audio unit in a logical order. It doesn't make sense to stop playback on an already uninitialized audio unit, which had in fact previously been disposed of in the middle of the playback. Rather than that, try the following order:
AudioOutputUnitStop(player.outputUnit); //first stops playback
AudioUnitUninitialize(player.outputUnit); //then deallocates unit's resources
AudioComponentInstanceDispose(player.outputUnit); //finally disposes of the AU itself
The sine wave command line app you're after is a well elaborated lesson in this textbook. Please read it step by step.
Last, but not least, your question has nothing to do with C++, CoreAudio is a plain-C API, so C++ in both your title and tag are wrong and misleading.

An Audio Unit runs in an asynchronous thread that may not actually stop immediately when you call AudioOutputUnitStop. Thus, it may work better to wait a fraction of a second (at least a couple audio callback buffer durations in time) before calling AudioUnitUninitialize and AudioComponentInstanceDispose on a potentially still running audio unit.
Also, check to make sure your player.outputUnit value is a valid unit (and not an uninitialized or trashed variable) at the time you stop the unit.

Related

Looping though a Buffer Array in Supercollider

I am trying to loop through an array of Buffers each containing a sound sample read from disk, but I am having problems getting the SynthDef to reset its pointer to the buffers.
I did the following:
Assume I have a folder of sound files and I have read them all into an array of Buffers called "~buffers"
I just want to go through the array in order, playing the samples back to back and stopping after the last one.
I define a simple SynthDef, and then put the Synth that calls it into a Routine:
(
SynthDef(\playBuffer,{arg out = 0, buf;
var sig;
sig = PlayBuf.ar(2, buf, doneAction: Done.freeSelf);
Out.ar(out, sig);
}).add
~routine = Routine({
~buffers.do({
arg item;
var synth;
synth = Synth(\playBuffer, [\buf, item]);
item.duration.wait;
synth.free;
});
});
~routine.play;
)
It does not work as expected---the synths are always playing the same sound,the first one, although for the durations corresponding to the different samples.
I think the problem could be that the function inside my \playbuffer SynthDef (at least according to the Help files) is not re-evaluated with a different bufnum argument inside the loop.
In fact I can loop through the buffers if I use Buffer.play which creates synthDef's and Synth's on the fly. Replacing my Routine with this code works:
(
~routine2 = Routine({
~buffers.do({
arg item;
item.play;
item.duration.wait;
});
});
~routine2.play;
)
BUT: it is very crude, as now I cannot manipulate the buffer output except for changing the amplitude through the mul parameter of Buffer.play.
What I would like to do is to replicate Buffer.play's behavior---creating SynthDef's and Synth's on the fly---in my own code. But I'm having no luck with it. In fact I am not sure where to start, possibly because I don't fully grasp SuperCollider's server's handling of functions. Should I make a Synth-making function and use that inside the routine's loop? Or should I move the definition of the SynthDef inside the loop (which seems equivalent)? I tried the latter, but still got the same sound playing.
Perhaps I am going at this the wrong way---I'm very new to SuperCollider.
The code in your first example is correct. If I fill by buffers like this:
(
s.makeBundle(nil, {
~buffers = [1, 2, 3, 4, 5].collect {
|i|
var b;
b = Buffer.alloc(s, 44100, 1);
b.sine3([100, 150, 175] * i, 0.25);
};
})
)
and then play them with your code example:
(
SynthDef(\playBuffer,{arg out = 0, buf;
var sig;
sig = PlayBuf.ar(1, buf, doneAction: Done.freeSelf);
Out.ar(out, sig);
}).add;
~routine = Routine({
~buffers.do({
arg item;
Synth(\playBuffer, [\buf, item]);
item.duration.wait;
});
});
~routine.play;
)
This works fine, I hear ascending tones. (I changed your example to be single channel buffers, and removed the .free as you were already doing Done.freeSelf). If you're hearing the same sound playing each time, the problem is likely in the code where you're loading your buffers and not in playback.
One gotcha: the duration property of a buffer is not available immediately after you load them - reading an audio file is asynchronous, and SC doesn't know the duration until it's loaded. If you're doing Buffer.read immediately before playing, there's a chance your duration might be e.g. 0 or nil, which would cause unexpected results.
i tryed it in a Task, but i think it is complitly like the think which you will do in routine.
you have to put the buffers in array.
like buffer=[1,2,3,4,5]
but it is better to code in this way.
\buffer=[a.bufnum,b.bufnum,c.bufnum,d.bufnum]
and set the buffer variable in second arrgument of PlayBuf in SynthDef.
because you might load others buffer in your server and if you put the number of the buffer in the array, it will usually play wrong buffer which you do not want to play,.

FMOD Ex dropping sounds, eventually going silent

I'm attempting to port an old open-source FMOD 3 game (Candy Crisis) to the latest version of FMOD Ex 4 on OS X. Its sound needs are very simple—it plays WAVs, sometimes changing their frequency or speaker mix, and also plays MOD tracker music, sometimes changing the speed. I'm finding that the game works fine at first, but over the course of a few minutes, it starts truncating sounds early, then the music loses channels and eventually stops, then over time all sound ceases. I can cause the problem to reproduce more quickly if I lower the number of channels available to FMOD.
I can get the truncated/missing sounds issue to occur even if I never play a music file, but music definitely seems to make things worse. I have also tried commenting out the code which adjusts the sound frequency and speaker mix, and that was not the issue.
I am calling update() every frame.
Here's the entirety of my interactions with FMOD to play WAVs:
void InitSound( void )
{
FMOD_RESULT result = FMOD::System_Create(&g_fmod);
FMOD_ERRCHECK(result);
unsigned int version;
result = g_fmod->getVersion(&version);
FMOD_ERRCHECK(result);
if (version < FMOD_VERSION)
{
printf("Error! You are using an old version of FMOD %08x. This program requires %08x\n", version, FMOD_VERSION);
abort();
}
result = g_fmod->init(8 /* was originally 64, but 8 repros the issue faster */, FMOD_INIT_NORMAL, 0);
FMOD_ERRCHECK(result);
for (int index=0; index<kNumSounds; index++)
{
result = g_fmod->createSound(QuickResourceName("snd", index+128, ".wav"), FMOD_DEFAULT, 0, &s_sound[index]);
FMOD_ERRCHECK(result);
}
}
void PlayMono( short which )
{
if (soundOn)
{
FMOD_RESULT result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_sound[which], false, NULL);
FMOD_ERRCHECK(result);
}
}
void PlayStereoFrequency( short player, short which, short freq )
{
if (soundOn)
{
FMOD::Channel* channel = NULL;
FMOD_RESULT result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_sound[which], true, &channel);
FMOD_ERRCHECK(result);
result = channel->setSpeakerMix(player, 1.0f - player, 0, 0, 0, 0, 0, 0);
FMOD_ERRCHECK(result);
float channelFrequency;
result = s_sound[which]->getDefaults(&channelFrequency, NULL, NULL, NULL);
FMOD_ERRCHECK(result);
result = channel->setFrequency((channelFrequency * (16 + freq)) / 16);
FMOD_ERRCHECK(result);
result = channel->setPaused(false);
FMOD_ERRCHECK(result);
}
}
void UpdateSound()
{
g_fmod->update();
}
And here's how I play MODs.
void ChooseMusic( short which )
{
if( musicSelection >= 0 && musicSelection <= k_songs )
{
s_musicChannel->stop();
s_musicChannel = NULL;
s_musicModule->release();
s_musicModule = NULL;
musicSelection = -1;
}
if (which >= 0 && which <= k_songs)
{
FMOD_RESULT result = g_fmod->createSound(QuickResourceName("mod", which+128, ""), FMOD_DEFAULT, 0, &s_musicModule);
FMOD_ERRCHECK(result);
result = g_fmod->playSound(FMOD_CHANNEL_FREE, s_musicModule, true, &s_musicChannel);
FMOD_ERRCHECK(result);
EnableMusic(musicOn);
s_musicModule->setLoopCount(-1);
s_musicChannel->setPaused(false);
musicSelection = which;
s_musicPaused = 0;
}
}
If someone wants to experiment with this, let me know and I'll upload the project somewhere. My gut feeling is that FMOD is busted but I'd love to be proven wrong.
Sounds like your music needs to be set as higher priority than your other sounds. Remember, lower numbers are more important. I think you can just set the priority on the channel.
Every time I play the following WAV, FMOD loses one channel permanently. I am able to reproduce this channel-losing behavior in the "playsound" example if I replace the existing jaguar.wav with my file.
https://drive.google.com/file/d/0B1eDRY8sV_a9SXMyNktXbWZOYWs/view?usp=sharing
I contacted Firelight and got this response. Apparently WAVs can include a looping command! I had no idea.
Hello John,
I've taken a look at the two files you have provided. Both files end
with a 2 sample infinite loop region.
FMOD 4 (and FMOD 5 for that matter) will see the loop region in the
file and automatically enable FMOD_LOOP_NORMAL if you haven't
specified any loop mode. Assuming you want one-shot behavior just pass
in FMOD_LOOP_OFF when you create the sound.
Kind regards, Mathew Block | Senior Platform Engineer
Technically this behavior contradicts the documented behavior of FMOD_DEFAULT (which is specified to imply FMOD_LOOP_OFF) so they are planning to improve the documentation here.
Based on the wave sample you supplied, FMOD is behaving correctly as it appears you've figured out. The sample has a loop that is honored by FMOD and the last samples are simply repeated forever. While useless, this is correct and the variance in the samples is so slight as to not be audible. While not part of the original spec for wave format, extended information was added later to support meta data such as author, title, comments and multiple loop points.
Your best bet is to examine all your source assets for those that contain loop information. Simply playing all sounds without loop information is probably not the best workaround. Some loops may be intentional. Those that are will have code that stops them. Typically, in a game, the entire waveform is looped when looping is desired. You can then write or use a tool that will strip the loop information. If you do write your own tool, I'd recommend resampling the audio to the native output sampling rate of the hardware. You'd need to insure your resampler was sample accurate (no time shift) and did not introduce noise.
Historically, some game systems had a section at the end of the sound with silence and a loop point set on this region. The short reason for this was to reduce popping that might occur at the end of a sound in a hardware audio channel.
Curiosly, the last 16 samples of your .wav look like garbage and I'm wondering if the .wav assets you're using were converted from a source meant for a game console and that's where the bogus loop information came from as well.
This would have been a comment but my lowly rep does not allow it.

Direct2D API calls stall at specific intervals

I am working on migrating the drawing code of an application from GDI/GDI+ to Direct2D. So far things have been going well - however, while testing the new code, I have noticed some bizarre performance. The flow of execution I have been investigating is as follows (I have done my best to remove irrelevant code):
Create D2D Factory (on creation of app)
HRESULT hr = S_OK;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, &m_pD2DFactory);
if (hr == S_FALSE) {
ASSERT(FALSE);
throw Exception(CExtString(_T("Failed to create Direct2D factory")));
}
OnDraw Callback
HWND hwnd = GetSafeHwnd();
RECT rc;
GetClientRect(&rc);
D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
// Create a render target if it has been destroyed
if (!m_pRT) {
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT);
GetD2DFactory()->CreateHwndRenderTarget(props,
D2D1::HwndRenderTargetProperties(hwnd, size),
&m_pRT);
}
m_pRT->Resize(size);
m_pRT->BeginDraw();
// Begin drawing the layers, given the
// transformation matrix and some geometric information
Draw(m_pRT, matrixD2D, rectClipWorld, rectClipDP);
HRESULT hr = m_pRT->EndDraw();
if (hr == D2DERR_RECREATE_TARGET) {
SafeRelease(m_pRT);
}
The contents of the Draw method
The draw method does a lot of fluff that is largely irrelevant to this test (as I have turned all extraneous layers off), but it eventually draws a layer that executes this method several thousand times:
void DrawStringWithEffects(ID2D1RenderTarget* m_pRT, const CString& text, const D2D1_POINT_2F& point, const COLORREF rgbFore, const COLORREF rgbBack, IDWriteTextFormat* pfont) {
// The text will be vertically centered around point.y, with point.x on the left hand side
// Create a TextLayout for the string
IDWriteTextLayout* textLayout = NULL;
GetDWriteFactory()->CreateTextLayout(text,
text.GetLength(),
pfont,
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
&textLayout);
DWRITE_TEXT_METRICS metrics = {0};
textLayout->GetMetrics(&metrics);
D2D1_RECT_F rect = D2D1::RectF(point.x, point.y - metrics.height/2, point.x + metrics.width, point.y + metrics.height/2);
D2D1_POINT_2F pointDraw = point;
pointDraw.y -= metrics.height/2;
ID2D1SolidColorBrush* brush = NULL;
m_pRT->CreateSolidColorBrush(ColorD2DFromCOLORREF(rgbBack), &brush);
m_pRT->FillRectangle(rect, brush);
// ^^ this is sometimes very slow!
brush->SetColor(ColorD2DFromCOLORREF(rgbFore));
m_pRT->DrawTextLayout(pointDraw, textLayout, brush, D2D1_DRAW_TEXT_OPTIONS_NONE);
// ^^ this is also sometimes very slow!
SafeRelease(&brush);
SafeRelease(&textLayout);
The vast majority of the time, the Direct2D calls are executing ~3-4 times faster than the GDI+ equivalents, which is great (generally 0.1ms compared to ~0.35ms). For some reason, though, the function calls will occasionally stall for a long period of time - upwards of 200ms combined. The offending calls are straight from the Direct2D API - FillRectangle and DrawTextLayout. Strangely, these stalls appear in the same location every time I run the application - the 73rd occurrence of the loop, then the 218th, then the 290th and so on (there is somewhat of a pattern in the differences, alternating between every ~73rd and every ~145th cycle). This is independent of the data that it draws (when I told it to skip drawing the 73rd cycle, the next cycle simply becomes the 73rd and thus stalls).
I thought this may be a GPU/CPU communication issue, so I set the render target (I am using an HWnd target) to software mode (D2D1_RENDER_TARGET_TYPE_SOFTWARE), and the results were even more strange. The stall times dropped from ~200ms to ~20ms (still not great, but hey), but there were two instances that stalled for over 2500ms! (These two, like the rest of the stalls, are completely reproducible in terms of being the n'th API call).
This is rather frustrating, as 99% of the loop is several times faster than the old implementation, but the (less than) 1% remaining hang for an abnormally long time.
To any Direct2D experts out there - what type of problem might this stalling be a symptom of? What, in general, could be causing this disconnect between my code and what D2D is doing in the background?
Direct2D buffers drawing commands (presumably to optimize them). You can't look at the performance of an individual drawing command, you must look at the total time between BeginDraw() and EndDraw(). If you want to force each drawing command to execute immediately, you must follow each one with a call to Flush(). That's probably a bad idea for performance though.
https://msdn.microsoft.com/en-us/library/windows/desktop/dd371768(v=vs.85).aspx
After BeginDraw is called, a render target will normally build up a
batch of rendering commands, but defer processing of these commands
until either an internal buffer is full, the Flush method is called,
or until EndDraw is called.

CFRunLoopSourceSignal doesn't work

I'm debugging Qt5.3.1 on Mac, because my program freezes sometimes (intermittent ). I discovered that it is because the QTimer can't work properly.
In Qt code, they use the following two lines to trigger function activateTimersSourceCallback
CFRunLoopSourceSignal(d->activateTimersSourceRef);
CFRunLoopWakeUp(mainRunLoop());
void QCocoaEventDispatcherPrivate::activateTimersSourceCallback(void *info)
{
static int counter = 0;
NSLog(#"finished activeteTimersSourceCallback %d", counter++);
}
but sometimes, these two lines doesn't work, activateTimersSourceCallback won't get called.
I googled, but I couldn't find any solution? is this a known OS bug?
the initialization details:
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
CFRunLoopSourceContext context;
bzero(&context, sizeof(CFRunLoopSourceContext));
context.info = d;
context.equal = runLoopSourceEqualCallback;
// source used to activate timers
context.perform = QCocoaEventDispatcherPrivate::activateTimersSourceCallback;
d->activateTimersSourceRef = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
Q_ASSERT(d->activateTimersSourceRef);
CFRunLoopAddSource(mainRunLoop(), d->activateTimersSourceRef, kCFRunLoopCommonModes);
Such behavior very likely can occur when UI event loop is overloaded with events or some business logic takes too long time. You should to check your business logic and move it to separate thread or run asynchronous.

In Cocoa, producing a tone at given frequency for given duration [duplicate]

I want to play Beep sound in my Mac Os X and specify duration and frequency. On Windows it can be done by using Beep function (Console.Beep in .Net). Is there anything equivalent in Mac? I am aware of NSBeep but it does not take any parameters.
On the Mac, the system alert sound is a sampled (prerecorded) sound that the user chooses. It often sounds nothing like a beep—it may be a honk, thunk, blare, or other sound that can't be as a simple constant waveform of fixed shape, frequency, and amplitude. It can even be a recording of the user's voice, or a clip from a TV show or movie or game or song.
It also does not need to be only a sound. One of the accessibility options is to flash the screen when an alert sound plays; this happens automatically when you play the alert sound (or a custom alert sound), but not when you play a sound through regular sound-playing APIs such as NSSound.
As such, there's no simple way to play a custom beep of a specified and constant shape, frequency, and amplitude. Any such beep would differ from the user's selected alert sound and may not be perceptible to the user at all.
To play the alert sound on the Mac, use NSBeep or the slightly more complicated AudioServicesPlayAlertSound. The latter allows you to use custom sounds, but even these must be prerecorded, or at least generated by your app in advance using more Core Audio code than is worth writing.
I recommend using NSBeep. It's one line of code to respect the user's choices.
PortAudio has cross platform C code for doing this here: https://subversion.assembla.com/svn/portaudio/portaudio/trunk/examples/paex_sine.c
That particular sample generates tones on the left and right speaker, but doesn't show how the frequencies are calculated. For that, you can use the formula in this code: Is there an library in Java for emitting a certain frequency constantly?
I needed a similar functionality for an app. I ended up writing a small, reusable class to handle this for me.
Source on GitHub
A reusable class for generating simple sine waveform audio tones with specified frequency and amplitude. Can play continuously or for a specified duration.
The interface is fairly straightforward and is shown below:
#interface TGSineWaveToneGenerator : NSObject
{
AudioComponentInstance toneUnit;
#public
double frequency;
double amplitude;
double sampleRate;
double theta;
}
- (id)initWithFrequency:(double)hertz amplitude:(double)volume;
- (void)playForDuration:(float)time;
- (void)play;
- (void)stop;
#end
Here's a way of doing this with the newer AVAudioEngine/AVAudioNode APIs, and Swift:
import AVFoundation
import Accelerate
// Specify the audio format we're going to use
let sampleRateHz = 44100
let numChannels = 1
let pcmFormat = AVAudioFormat(standardFormatWithSampleRate: Double(sampleRateHz), channels: UInt32(numChannels))
let noteFrequencyHz = 440
let noteDuration: NSTimeInterval = 1
// Create a buffer for the audio data
let numSamples = UInt32(noteDuration * Double(sampleRateHz))
let buffer = AVAudioPCMBuffer(PCMFormat: pcmFormat, frameCapacity: numSamples)
buffer.frameLength = numSamples // the buffer will be completely full
// The "standard format" is deinterleaved float, so we can assume the stride is 1.
assert(buffer.stride == 1)
for channelBuffer in UnsafeBufferPointer(start: buffer.floatChannelData, count: numChannels) {
// Generate a sine wave with the specified frequency and duration
var length = Int32(numSamples)
var dc: Float = 0
var multiplier: Float = 2*Float(M_PI)*Float(noteFrequencyHz)/Float(sampleRateHz)
vDSP_vramp(&dc, &multiplier, channelBuffer, buffer.stride, UInt(numSamples))
vvsinf(channelBuffer, channelBuffer, &length)
}
// Hook up a player and play the buffer, then exit
let engine = AVAudioEngine()
let player = AVAudioPlayerNode()
engine.attachNode(player)
engine.connect(player, to: engine.mainMixerNode, format: pcmFormat)
try! engine.start()
player.scheduleBuffer(buffer, completionHandler: { exit(1) })
player.play()
NSRunLoop.mainRunLoop().run() // Keep running in a playground

Resources