Added custom WAV loader

This commit is contained in:
Nicolay Korslund 2010-08-18 12:32:38 +02:00
parent 27bef84091
commit 8f154ac622
8 changed files with 303 additions and 1 deletions

View file

@ -0,0 +1,40 @@
#ifndef MANGLE_VARIOUS_OPENAL_H
#define MANGLE_VARIOUS_OPENAL_H
#include "input_filter.hpp"
#include "source_splicer.hpp"
#include "../sources/mpg123_source.hpp"
#include "../sources/wav_source.hpp"
#include "../outputs/openal_out.hpp"
namespace Mangle {
namespace Sound {
/** A InputFilter that uses OpenAL for output, and load input from
various individual sources, depending on file extension. Currently
supports:
MP3: mpg123
WAV: custom wav loader (PCM only)
This could be an alternative to using eg. libsndfile or other 3rd
party decoder libraries. (We implemented this for OpenMW because
we were experiencing crashes when using libsndfile.)
*/
class OpenAL_Various_Factory : public InputFilter
{
public:
OpenAL_Various_Factory()
{
SourceSplicer *splice = new SourceSplicer;
splice->add("mp3", SampleSourceLoaderPtr(new Mpg123Loader));
splice->add("wav", SampleSourceLoaderPtr(new WavLoader));
set(SoundFactoryPtr(new OpenAL_Factory),
SampleSourceLoaderPtr(splice));
}
};
}}
#endif

View file

@ -0,0 +1,95 @@
#include "wav_source.hpp"
#include "../../tools/str_exception.hpp"
#include "../../stream/servers/file_stream.hpp"
using namespace Mangle::Stream;
using namespace Mangle::Sound;
static void fail(const std::string &msg)
{ throw str_exception("Mangle::Wav exception: " + msg); }
void WavSource::getInfo(int32_t *pRate, int32_t *pChannels, int32_t *pBits)
{
// Use the values we found in the constructor
*pRate = rate;
*pChannels = channels;
*pBits = bits;
}
void WavSource::seek(size_t pos)
{
// Seek the stream and set 'left'
assert(isSeekable);
if(pos > total) pos = total;
input->seek(dataOffset + pos);
left = total-pos;
}
size_t WavSource::read(void *data, size_t length)
{
if(length > left)
length = left;
input->read(data, length);
return length;
}
void WavSource::open(Mangle::Stream::StreamPtr data)
{
input = data;
hasPosition = true;
hasSize = true;
// If we can check position and seek in the input stream, then we
// can seek the wav data too.
isSeekable = input->isSeekable && input->hasPosition;
// Read header
unsigned int val;
input->read(&val,4); // header
if(val != 0x46464952) // "RIFF"
fail("Not a WAV file");
input->read(&val,4); // size (ignored)
input->read(&val,4); // file format
if(val != 0x45564157) // "WAVE"
fail("Not a valid WAV file");
input->read(&val,4); // "fmt "
input->read(&val,4); // chunk size (must be 16)
if(val != 16)
fail("Unsupported WAV format");
input->read(&val,2);
if(val != 1)
fail("Non-PCM (compressed) WAV files not supported");
// Sound data specification
channels = 0;
input->read(&channels,2);
input->read(&rate, 4);
// Skip next 6 bytes
input->read(&val, 4);
input->read(&val, 2);
// Bits per sample
bits = 0;
input->read(&bits,2);
input->read(&val,4); // Data header
if(val != 0x61746164) // "data"
fail("Expected data block");
// Finally, read the data size
input->read(&total,4);
left = total;
// Store the beginning of the data block for later
if(input->hasPosition)
dataOffset = input->tell();
}
WavSource::WavSource(const std::string &file)
{ open(StreamPtr(new FileStream(file))); }

View file

@ -0,0 +1,49 @@
#ifndef MANGLE_SOUND_WAV_SOURCE_H
#define MANGLE_SOUND_WAV_SOURCE_H
#include "../source.hpp"
#include <assert.h>
namespace Mangle {
namespace Sound {
/// WAV file decoder. Has no external library dependencies.
class WavSource : public SampleSource
{
// Sound info
uint32_t rate, channels, bits;
// Total size (of output) and bytes left
uint32_t total, left;
// Offset in input of the beginning of the data block
size_t dataOffset;
Mangle::Stream::StreamPtr input;
void open(Mangle::Stream::StreamPtr);
public:
/// Decode the given sound file
WavSource(const std::string&);
/// Decode from stream
WavSource(Mangle::Stream::StreamPtr s)
{ open(s); }
void getInfo(int32_t *rate, int32_t *channels, int32_t *bits);
size_t read(void *data, size_t length);
void seek(size_t);
size_t tell() const { return total-left; }
size_t size() const { return total; }
bool eof() const { return left > 0; }
};
#include "loadertemplate.hpp"
/// A factory that loads WavSources from file and stream
typedef SSL_Template<WavSource,true,true> WavLoader;
}} // Namespace
#endif

View file

@ -1,12 +1,18 @@
GCC=g++ -I../ -Wall
all: audiere_source_test ffmpeg_source_test openal_output_test openal_audiere_test openal_ffmpeg_test openal_mpg123_test openal_sndfile_test
all: audiere_source_test ffmpeg_source_test openal_output_test openal_audiere_test openal_ffmpeg_test openal_mpg123_test openal_sndfile_test wav_source_test openal_various_test
L_FFMPEG=$(shell pkg-config --libs libavcodec libavformat)
I_FFMPEG=-I/usr/include/libavcodec -I/usr/include/libavformat
L_OPENAL=$(shell pkg-config --libs openal)
L_AUDIERE=-laudiere
wav_source_test: wav_source_test.cpp ../sources/wav_source.cpp
$(GCC) $^ -o $@
openal_various_test: openal_various_test.cpp ../sources/mpg123_source.cpp ../sources/wav_source.cpp ../outputs/openal_out.cpp
$(GCC) $^ -o $@ -lmpg123 ${L_OPENAL}
openal_audiere_test: openal_audiere_test.cpp ../sources/audiere_source.cpp ../sources/sample_reader.cpp ../outputs/openal_out.cpp ../../stream/clients/audiere_file.cpp
$(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL)

View file

@ -0,0 +1,51 @@
#include <iostream>
#include <exception>
#include "../../stream/servers/file_stream.hpp"
#include "../filters/openal_various.hpp"
using namespace std;
using namespace Mangle::Stream;
using namespace Mangle::Sound;
OpenAL_Various_Factory mg;
void play(const char* name, bool stream=false)
{
// Only load streams if the backend supports it
if(stream && !mg.canLoadStream)
return;
cout << "Playing " << name;
if(stream) cout << " (from stream)";
cout << "\n";
SoundPtr snd;
try
{
if(stream)
snd = mg.load(StreamPtr(new FileStream(name)));
else
snd = mg.load(name);
snd->play();
while(snd->isPlaying())
{
usleep(10000);
if(mg.needsUpdate) mg.update();
}
}
catch(exception &e)
{
cout << " ERROR: " << e.what() << "\n";
}
}
int main()
{
play("cow.wav");
play("cow.wav", true);
return 0;
}

View file

@ -0,0 +1 @@
Playing cow.wav

View file

@ -0,0 +1,12 @@
Source size: 37502
rate=11025
channels=1
bits=16
Reading entire buffer into memory
Reading cow.raw
Size: 37502
Comparing...
Done

View file

@ -0,0 +1,48 @@
#include <iostream>
#include "../sources/wav_source.hpp"
#include "../../stream/servers/file_stream.hpp"
#include <assert.h>
#include <string.h>
using namespace std;
using namespace Mangle::Sound;
using namespace Mangle::Stream;
int main()
{
WavSource wav("cow.wav");
cout << "Source size: " << wav.size() << endl;
int rate, channels, bits;
wav.getInfo(&rate, &channels, &bits);
cout << "rate=" << rate << "\nchannels=" << channels
<< "\nbits=" << bits << endl;
cout << "Reading entire buffer into memory\n";
void *buf = malloc(wav.size());
wav.read(buf, wav.size());
cout << "\nReading cow.raw\n";
FileStream tmp("cow.raw");
cout << "Size: " << tmp.size() << endl;
void *buf2 = malloc(tmp.size());
tmp.read(buf2, tmp.size());
cout << "\nComparing...\n";
if(tmp.size() != wav.size())
{
cout << "SIZE MISMATCH!\n";
assert(0);
}
if(memcmp(buf, buf2, wav.size()) != 0)
{
cout << "CONTENT MISMATCH!\n";
assert(0);
}
cout << "\nDone\n";
return 0;
}