Trying to playback an audio file (newbie)


#1

I’ve been reading the documentation and opened the JuceDemo project (AudioDemoPlaybackPage.cpp).
Tried to re-do what’s in this file but things such as setting transport source thread, I just couldn’t find them in the code.
This is what I got so far but no sound can be heard yet :

[code] //==============================================================================
void initialise (const String& commandLine)
{
// Do your application’s initialisation code here…
mainWindow = new MainAppWindow();

	// Load a file
	File & currentDir = File::getCurrentWorkingDirectory();
	File & audioFile = currentDir.getChildFile("Didier Sinclair - Lovely Flight.wav");
	
	// Create required classes for playback :

	/* Manager */
	AudioFormatManager *formatManager = new AudioFormatManager();
	formatManager->registerBasicFormats();

	/* Reader */
	AudioFormatReader *reader =	formatManager->createReaderFor(audioFile);

	/* ReaderSource */
	AudioFormatReaderSource *source = new AudioFormatReaderSource(reader, true);

	/* TransportSource */
	AudioTransportSource *transport = new AudioTransportSource();
	transport->setSource(source, 0, nullptr, 0.0, 2);
	transport->start();

	/* SourcePlayer */
	AudioSourcePlayer *player = new AudioSourcePlayer();
	player->setSource(transport);
}[/code]

Thank you.


#2

You have to create an AudioDeviceManager, initialize it, and add the player as a callback to the device manager.


#3

I have sound now !

But when I exit my application, I am told there are leaked objects (I’ve only put the first 3)

*** Leaked objects detected: 1 instance(s) of class DSoundAudioIODeviceType
*** Leaked objects detected: 2 instance(s) of class HeapBlock
*** Leaked objects detected: 1 instance(s) of class WASAPIAudioIODeviceType

[code] AudioFormatManager *audioFormatManager;
AudioFormatReader *audioFormatReader;
ScopedPointer audioFormatReaderSource;
AudioTransportSource *audioTransportSource;
AudioSourcePlayer *audioSourcePlayer;
AudioDeviceManager *audioDeviceManager;

//==============================================================================
void initialise (const String& commandLine)
{
	// Do your application's initialisation code here..
	mainWindow = new MainAppWindow();

	// Load a file
	File & currentDir = File::getCurrentWorkingDirectory();
	File & audioFile = currentDir.getChildFile("Didier Sinclair - Lovely Flight.wav");
	
	/* Create required classes for playback */

	// Format manager
	audioFormatManager = new AudioFormatManager();
	audioFormatManager->registerBasicFormats();

	// Format reader
	audioFormatReader =	audioFormatManager->createReaderFor(audioFile);

	// Reader source
	audioFormatReaderSource = new AudioFormatReaderSource(audioFormatReader, true);

	// Transport source
	audioTransportSource = new AudioTransportSource();
	audioTransportSource->setSource(audioFormatReaderSource, 0, nullptr, 44100.0, 2);
	audioTransportSource->start();

	// Source player
	audioSourcePlayer = new AudioSourcePlayer();
	audioSourcePlayer->setSource(audioTransportSource);

	// Device manager
	audioDeviceManager = new AudioDeviceManager();
	audioDeviceManager->initialise(2, 2, 0, true);
	audioDeviceManager->addAudioCallback(audioSourcePlayer);
}

void shutdown()
{
	// Do your application's shutdown code here..
	mainWindow = 0;
}

//==============================================================================
void systemRequestedQuit()
{
	audioTransportSource->stop();
	audioTransportSource->setSource(nullptr);

	audioSourcePlayer->setSource(nullptr);
	
	audioDeviceManager->removeAudioCallback(audioSourcePlayer);
	audioDeviceManager->closeAudioDevice();

	quit();
}[/code]

I’ve tried ScopedPointer class as in the examples but it didn’t change anything.

Could you explain what is the procedure for deleting objects in general, in JUCE ?

Thank you.


#4

SimpleDJ, in my signature, provides full source for playing back audio files with the audio device manager.


#5

Great, i’ll have a look.

I myself wrote a DJ-ing software in C# :wink:
http://www.youtube.com/watch?v=k6WBW2QaydA

Thanks.


#6

If you don’t understand basic C++ memory management, then you need to stop whatever else you’re doing, and go and really thoroughly learn about it before carrying on. There’s no point trying to just pick it up as you go along, you’ll just waste a lot of time that way.


#7

If you don’t understand basic C++ memory management, then you need to stop whatever else you’re doing, and go and really thoroughly learn about it before carrying on. There’s no point trying to just pick it up as you go along, you’ll just waste a lot of time that way.[/quote]

I come from the garbage-collected world of C# … Maybe you can redirect me to some good readings about it ?

Thank you.


#8

“C++ How to Program” ,Paul Deitel, Harvey Deitel
"C++ Primer",Stanley B.Lippman…
“Effective C++ / More Effective C++”,Scott Meyers
"The C++ Programming Language",Bjarne Stroustrup
… …

JUCE-Demo source code, Jules
dRowAudio class library source code, Dave96
JUCE class library source code, Jules


#9

http://www.rawmaterialsoftware.com/wiki/index.php/Learning_C%2B%2B


#10

Well, that’s an ambitious reading list.

It can be recapped more succinctly as - C++ does no memory allocation or deletion for you.
The C++ ‘new’ and ‘delete’ operators create and delete C++ object instances.
As in C, floating pointers, pointer de-referencing, and memory leaks are big, big problems.
Modern C++ techniques, used wherever possible, make this problem far easier.

So, read a bit on RAII, then look at Juce classes like:
ScopedPointer
OwnedArray
WeakReference
ReferenceCountedObject (plus Pointer and array)

Use them above all else, and if for some reason you can’t, be very conscious of your object lifetimes and ownership. Be aware that C++ has some mechanisms - i.e. exceptions, that make only the above classes the only viable way to make a high quality app.

Bruce


#11

Thank you for the links, I’ve started reading some of them.

In the mean time I’ve finished my first JUCE app !

here it is http://www.sharpmix.com/?p=79 :slight_smile:


#12

I’d love to see this up on Github!


#13

Ok, I’ll put it sometimes next week, have to clean it before.

That’s funny because I just set up my first GitHub account yesterday,
I’ve uploaded my first library here https://github.com/aybe/GLA

In the mean time if someone fluent in JUCE can see the code and tell anything wrong,
I’ve spent quite some time trying to avoid ‘new’ as said in the docs,
but I concluded that it’s (mostly) unavoidable at least for my case,
pretty much all members are global, I couldn’t initialize them like int i(0);
I couldn’t put the AudioFormatReader in a ScopedPointer, in the samples it’s like that
so I left it as is.

Beside that I’ve seen how ScopedPointer works when cleaning stuff,
read a few docs etc but it’ll still take some time for me to digest all that,
at least now JUCE does not complain about leaks when I exit the program !

Oh and yes, I thought I could reduce compilation time by removing some modules,
build time did not improve much but my executable got bigger, how come ?

	ScopedPointer<AudioFormatManager> audioFormatManager;
	AudioFormatReader* audioFormatReader;
	ScopedPointer<AudioFormatReaderSource> audioFormatReaderSource;
	ScopedPointer<AudioTransportSource> audioTransportSource;
	ScopedPointer<AudioSourcePlayer> audioSourcePlayer;
	ScopedPointer<AudioDeviceManager> audioDeviceManager;
	ScopedPointer<MyTimer1> myTimer1;
	ScopedPointer<Image>  _image;
	ScopedPointer<ImageComponent> _imageComponent;

	//==============================================================================
	void initialise (const String& commandLine)
	{
		// Do your application's initialisation code here..
		mainWindow = new MainAppWindow();
		//mainWindow->setResizable(false, false);
		//mainWindow->setResizeLimits(256, 256, 256, 256);

		// Load a file
		File & currentDir = File::getCurrentWorkingDirectory();
		File & audioFile = currentDir.getChildFile("audio.mp3");

		/* Create required classes for playback */

		if (audioFile.exists())
		{
			audioFormatManager = (new AudioFormatManager());
			audioFormatManager->registerBasicFormats();

			audioFormatReader = (audioFormatManager->createReaderFor(audioFile));

			audioFormatReaderSource = (new AudioFormatReaderSource(audioFormatReader,true));

			audioTransportSource = (new AudioTransportSource());
			audioTransportSource->setSource(audioFormatReaderSource, 0, nullptr, 44100.0, 2);
			audioTransportSource->start();

			audioSourcePlayer = (new AudioSourcePlayer());
			audioSourcePlayer->setSource(audioTransportSource);

			audioDeviceManager = (new AudioDeviceManager());
			audioDeviceManager->initialise(2, 2, 0, true);
			audioDeviceManager->addAudioCallback(audioSourcePlayer);
		}

		_image = new Image(Image::ARGB,256,256,true);
		_imageComponent = new ImageComponent();
		_imageComponent->setBounds(0, 0, 256, 256);
		_imageComponent->setImage(*_image);

		mainWindow->setContentNonOwned(_imageComponent, true);

		myTimer1 = (new MyTimer1(_imageComponent));
		myTimer1->startTimer((int)(1.0f / 30 * 1000));
	}

	//==============================================================================
	void systemRequestedQuit()
	{
		if (myTimer)
		{
			myTimer->stopTimer();
		}

		if (myTimer1)
		{
			myTimer1->stopTimer();
		}

		if (audioTransportSource)
		{
			audioTransportSource->stop();
			audioTransportSource->setSource(nullptr);
		}

		if (audioDeviceManager)
		{
			audioDeviceManager->removeAudioCallback(audioSourcePlayer);
			audioDeviceManager->closeAudioDevice();
		}

		quit();
	}

#14

[quote]I’ve spent quite some time trying to avoid ‘new’ as said in the docs,
but I concluded that it’s (mostly) unavoidable at least for my case,[/quote]

Well, your conclusions are way off, I’m afraid. I’ve no time to give you a tutorial on basic c++ object management, but at a quick glance I’d say almost all of the pointers in that code snippet could be avoided. (The Image class is a pass-by-value type, for heaven’s sake!)


#15

Ok, I’ll dig onto this, thanks.


#16

Have you not tried doing the following; declaring the objects on the stack?!

AudioDeviceManager audioDeviceManager;
AudioSourcePlayer audioSourcePlayer;
AudioTransportSource audioTransportSource;
AudioFormatManager audioFormatManager;
(etc...)

To add, say, the audioSourcePlayer to the device callbacks of audioDeviceManager:

audioDeviceManager.addAudioCallback (&audioSourcePlayer); //Note the usage of the ampersand ('&') character.

Similarly, setting the juce::AudioSource of the audioSourcePlayer with the audioTransportSource:

audioSourcePlayer.setSource (&audioTransportSource); //Note the usage of the ampersand ('&') character here, too.

You need to research pointers and references; a major component of the C++ language. In C#, the concepts are pretty well the same, as long as you have your project set to unsafe. But C# also has the ref keyword that emulates references in function parameters…


#17

What am I supposed to do, if I need to use one of these classes when I have returned
from the method that did declare it on the stack ? Do I create another one with same params ?

Okay but where do you get these AudioSourcePlayer and AudioTransportSource from ?

[quote=“jrlanglois”]
You need to research pointers and references; a major component of the C++ language. In C#, the concepts are pretty well the same, as long as you have your project set to unsafe. But C# also has the ref keyword that emulates references in function parameters…[/quote]
I know these concepts, not totally comfortable with pointers yet but I used them many times.
But in C# I’d say they are somewhat easier to use, they’re rarely needed and often for the same things,
mostly when writing pixels to a surface or feed a buffer with audio data. (in my case)

I clearly need to buy a book, like I did with C# when I really progressed,
it was Programming C# 3.0 By Jesse Liberty, Donald Xie, a very good book.

I also need to get a good JUCE sample and spend a few hours studying it …

Ok I’ll give an update to my code next after I’ve documented myself,
I’ll post my code and you’ll tell me if I got it right.

Thank you


#18

When you create objects on the stack (as opposed to the heap, with ‘new’) then they are instantiated and their constructor is run when they enter scope, much like a normal variable. When they leave scope the destructor is run for you.

In the case of a class that has members that are class types, they are all created when the holding class is instantiated (created). In fact, if the constructors need parameters, you specify them in the constructor of the holding class.

But yes, anyway, a C++ book is a good idea.

Bruce


#19

Aybe, you had posted this code, right?

   ScopedPointer<AudioFormatManager> audioFormatManager;
   AudioFormatReader* audioFormatReader;
   ScopedPointer<AudioFormatReaderSource> audioFormatReaderSource;
   ScopedPointer<AudioTransportSource> audioTransportSource;
   ScopedPointer<AudioSourcePlayer> audioSourcePlayer;
   ScopedPointer<AudioDeviceManager> audioDeviceManager;
   ScopedPointer<MyTimer1> myTimer1;
   ScopedPointer<Image>  _image;
   ScopedPointer<ImageComponent> _imageComponent;

All those objects are within the same scope… If you declare them on the stack like I did (aka; avoid the usage of ScopedPointer and pointers where possible so you don’t declare such on the heap via “new”), you can then use the couple LOCs I posted just previously to link some objects together to create a system.


#20

Alright, thanks.

(I definitely need to spend some time debugging and looking at members/life-time of objects.)