Processing audio in console application - main()?

Hello,

I am working on a console application that processes input and pushes that to the output. Let’s say for example just applying some gain to the input.

I have made it as an GUI application but I have troubles putting it into a console application.

The binding between App classes and console applications is unclear to me.

To be more specific, I don’t see how I have to implement the AudioComponent class within main() and access getNextAudioBlock from there.

I am not sure if the problem is my novice C++ understanding or if it is just complicated but I feel there is not much info in the tutorials nor in the forum regarding Console Applications.

Feel free to dis me for my C++ skills but any advice is welcome and an example with a simple “input->processing->output” would be super helpful.

Thanks a lot in advance!

EDIT: Push to the output is not a proper way to say it, I mean realtime processing in terms of buffer.

Just don’t use the AudioAppComponent, that’s meant only for GUI applications. You need to use AudioDeviceManager and implement a AudioIODeviceCallback subclass to do your audio processing and pass that into the AudioDeviceManager.

Just for clarification first, if you say “push to the output”, you mean playing it back through an audio device or writing it into a file?

For offline processing and writing into a file, it might be ok to do everything in the main() method, but to use the audio interfaces, you should use the message manager to have the separation between audio thread and user interaction, if there is any.

The classes you might want to look at in this case are the player classes: AudioSourcePlayer or AudioProcessorPlayer.

HTH

Thanks for the reply, I just edited my question just to clarify that I mean real time processing in terms of buffer manipulation.

I kind of managed to read and play a file but haven’t yet found out how to tweak that to process input.

Like @Xenakios said, you will need an AudioDeviceManager and connect a (or several) AudioIODeviceCallbacks to it. But you don’t need to write them yourself, the players I linked before inherit AudioIODeviceCallback and will do the trick, until you need some specialisations.

Thank you guys for your help, although it took me a lot of time to figure out how to use the information you provided me. Just to share how I dealt with the problem, I post the class and the main function I made in the end of the post.

Yet, I am now getting some memory leakage issue every time I quit the application (after some time) which I cannot figure out. But I will continue that in a separate thread.

Main.cpp

#include “…/JuceLibraryCode/JuceHeader.h”
#include “audioclass.h”

int main (int argc, char* argv[])
{
initialiseJuce_GUI();
AudioClass ac; // The custom class I have made
DBG(“press ‘Q’ to stop”);
while (auto c = getchar())
{
if (c == ‘q’ || c == ‘Q’)
{
break;
}
}
shutdownJuce_GUI();
return 0;
}

audioclass.h

#pragma once
#include “…/JuceLibraryCode/JuceHeader.h”

class AudioClass : public AudioIODeviceCallback
{
public:
AudioDeviceManager deviceManager;
AudioClass()
{
DBG(“AudioClass”);
deviceManager.initialise(2, 2, nullptr, true);
deviceManager.addAudioCallback(this);
}

~AudioClass()
{
DBG("~AudioClass");
deviceManager.removeAudioCallback(this);
}

void audioDeviceIOCallback(const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples)
{
for (int channi = 0; channi < numOutputChannels; channi++)
{
for (int i = 0; i < numSamples; i++)
{
outputChannelData[channi][i] = inputChannelData[channi][i] * 1000;
}
}
}

void audioDeviceAboutToStart(AudioIODevice* device)
{
DBG("audioDeviceAboutToStart:\nDevice : " << device->getName() << "\nSampleRate : " << device->getCurrentSampleRate() << "\nBufferSize : " << device->getCurrentBufferSizeSamples());
}

void audioDeviceStopped()
{
DBG(“audioDeviceStopped”);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(AudioClass)
};

I can see that the program fails without calling initialiseJuce_GUI(); but isn’t there a more intuitive way to do it? Calling initialize gui on a console only app doesn’t really feel right.

Would that be another way to spawn a threat instead?

If you look into the implementation of initialiseJuce_GUI, you will see the only thing it does is to get an instance of the messagemanager. (In order to initialize it.) So the function is maybe a bit misnamed but it doesn’t really do anything GUI specific.

1 Like

So would I be able to just call
MessageManager::getInstance();
and
DeletedAtShutdown::deleteAll();
MessageManager::deleteInstance(); ?

This JUCE_AUTORELEASEPOOL really confuses me.

[UPDATE]
The following works:

MessageManager::getInstance();
//initialiseJuce_GUI();

audio_class ac; // The custom class I have made
DBG("press 'Q' to stop");
while(true)
{ /* whatever */ }

//shutdownJuce_GUI();
DeletedAtShutdown::deleteAll();
MessageManager::deleteInstance();

I wonder if omitting the macro causes any issue tho.

The auto release pool thing is for Apple compilers and platforms.

The RAII solution is ScopedJuceInitialiser_GUI:

int main(int, char**)
{
    ScopedJuceInitialiser_GUI initialiser;
    // do your stuff
    return 0;
    // end of scope triggers clean up
}
1 Like

But that still has “GUI” written in it… :wink:

1 Like

I didn’t name it :stuck_out_tongue:

Since the MessageManager hooks up into the windows/OS/Xorg event queue, the name might not be so far off, there is just no window…

You could argue that the console window has sort of a GUI :stuck_out_tongue:

It is possible to write “real” console applications, but then you cannot use anything, that uses events (basically everything that relies on MessageManager):

  • Timer (you can use HighResolutionTimer though)
  • AsyncUpdater
  • InterProcessConnection (you can switch to synchronous calls though)
  • callAsync and callAfterDelay (obviously :wink: )
  • AudioTransportSource

And many more things use Timer and AsyncUpdater behind the scenes, so you have to look into each one you use…

@daniel so what would your approach be if you had a mature real-time application that needs a better audio system and you can’t change anything else aside from the audio library? (currently a dynamically loaded dll)