date: Nov 10, 2003
author: Pau Arumí

Ease the 'loading whole file into an audio' Use Case

What's Wrong?

In few words: (a) too complicated to read the whole file to an audio because the user needs to do explicit things that could be made implicitly. And (b) use of AudioFileIn concrete methods (Size() and SampleRate()) is unavoidable.

Code example taken from examples/FilePlayback_example.cxx (simplified version). Marked in bold is the code, I think, we'd try to avoid:

		CLAM::AudioFileIn   fileLoader;
		CLAM::AudioFileConfig fileLoaderConfig;
		const char* filename = fl_file_chooser( "Please, select a .wav file", "*.wav", NULL );

		fileLoaderConfig.SetFilename( filename );
		fileLoaderConfig.SetFiletype( CLAM::EAudioFileType::eWave );

		CLAM_ASSERT( fileLoader.Configure( fileLoaderConfig ), " ERROR: could not open audio file" );
		
		CLAM::TSize nSamples = fileLoader.Size();
		CLAM::TData sampleRate = fileLoader.SampleRate();

		CLAM::Audio   signalChannel;

		signalChannel.SetSize( nSamples );

		// Let's assume the audio is mono
  		CLAM_ASSERT( fileLoader.Channels() == 1, "mono file expected" );

		fileLoader.Start();
		fileLoader.Do( signalChannel );
		fileLoader.Stop();
	

Apart from being a tough code for doing a thing that otherwise could be done with very few lines, the fact that concrete methods are needed (Size, SampleRate) makes this use case out of the supervised-mode (network) mode. Actually it can be worked out using streaming, but I'm o the opinion that in general non-generic public methods in processings should be avoided.

Proposed solution

Add a new boolean attribute to the AudioFileConfig, for example: ReadWholeFile, which tells the AudioFileIn object that when its Do is called, it must do the necessary with the passed Audio in order to read the whole file. That means basically resizing the audio and setting sample rate.

An AudioFileIn object should be able to automatically determine the format (wav, raw, etc) of the file passed in configuration. Thus, easing the configuration code the user has to write.

The same applies for the sample rate of the file.

Code of proposed solution:

		CLAM::AudioFileIn   fileLoader;
		CLAM::AudioFileConfig fileLoaderConfig;
		const char* filename = fl_file_chooser( "Please, select a .wav file", "*.wav", NULL );

		fileLoaderConfig.SetFilename( filename );
		fileLoaderConfig.SetReadWholeFile( true );
		CLAM_ASSERT( fileLoader.Configure( fileLoaderConfig ), " ERROR: could not open audio file" );

		CLAM::Audio   signalChannel;
		// Let's assume the audio is mono
  		CLAM_ASSERT( fileLoader.GetInControls("channels").LastValue() == 1, "mono file expected" );

		fileLoader.Start();
		fileLoader.Do( signalChannel );
		fileLoader.Stop();
	

Notice the way of avoiding concrete method GetChannels

The proposed ReadWholeFile attribute is also (very) useful for AudioFileOut. In this case the client code will not have to split a long audio files in chunks in order to store it in a file.

Remove concrete methods (GetSize(), SampleRate(), GetChannels(), more?). Of course this can be done with a transition process.

Backward compatibility

Only the last point (remove GetSize) will break compatibility. The rest are non conflictive additions of functionality.

How to make the transition in client code?

Not removing GetSize for a while. But marking it as depracated

Revising all the 'load whole file to an audio' cases of user code and simplifying it by hand. A very easy and short user-guide could be provided.

The same for 'saving whole audio to a file' use case.