Hi,
I’m trying to do extensive use of InputStreams everywhere I can to abstract the source type…
It works well with the Image class, but I have a problem with audio files when creating an AudioFormatReader.
There is no way to know the audio format of a stream directly from the AudioFormatManager, so here is what I was doing :
AudioFormatReader* createReaderFor(InputStream*& stream)
{
AudioFormatManager afm;
afm.registerBasicFormats();
for (int i = 0; i < afm.getNumKnownFormats(); ++i)
{
AudioFormatReader* afr = afm.getKnownFormat(i)->createReaderFor(stream);
if (afr)
return afr; // found
else
stream = recreateStream(); // stream has been deleted by afr
}
return 0;
}
- The stream is deleted if it is not suitable, and that makes the code ugly cause I have to recreate the stream every time (simplified here).
- The flac audio format asserts juce_FlacAudioFormat.cpp, line 101 if the stream is not is cup of tea.
So here is what I added this to Juce :
// In class AudioFormat :
/** Returns true if this given stream can be read by this format.
Subclasses should read some bytes of the stream to decide if it looks good enough.
*/
virtual bool canHandleStream (InputStream* sourceStream) = 0;
// And for each formats :
bool AiffAudioFormat::canHandleStream (InputStream* input)
{
int64 begin = input->getPosition();
bool looksCorrect = false;
if (input->readInt() == chunkName ("FORM"))
{
if (input->readInt())
{
const int nextType = input->readInt();
if (nextType == chunkName ("AIFF") || nextType == chunkName ("AIFC"))
{
looksCorrect = true;
}
}
}
input->setPosition(begin);
return looksCorrect;
}
bool FlacAudioFormat::canHandleStream (InputStream* input)
{
int64 begin = input->getPosition();
bool looksCorrect = false;
if (input->readInt() == chunkName ("fLaC"))
{
looksCorrect = true;
}
input->setPosition(begin);
return looksCorrect;
}
bool OggVorbisAudioFormat::canHandleStream (InputStream* input)
{
int64 begin = input->getPosition();
bool looksCorrect = false;
if (input->readInt() == chunkName ("OggS"))
{
looksCorrect = true;
}
input->setPosition(begin);
return looksCorrect;
}
bool WavAudioFormat::canHandleStream (InputStream* input)
{
int64 begin = input->getPosition();
bool looksCorrect = false;
if (input->readInt() == chunkName ("RIFF"))
{
if (input->readInt())
{
if (input->readInt() == chunkName ("WAVE"))
{
looksCorrect = true;
}
}
}
input->setPosition(begin);
return looksCorrect;
}
So now it is possible to do this :
static AudioFormatReader* audio_from_stream(InputStream* stream)
{
static AudioFormatManager afm;
if (afm.getNumKnownFormats() == 0)
afm.registerBasicFormats();
for (int i = 0; i < afm.getNumKnownFormats(); ++i)
if (afm.getKnownFormat(i)->canHandleStream(stream))
return afm.getKnownFormat(i)->createReaderFor(stream);
return NULL;
}
I couldn’t make extensive tests, but it works for the sample files I have in the four formats.