mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
Major developments to love.audio/love.sound. Music and Sound are gone. There are only Sources now, which is much cleaner.
The audio module was not really stable in 0.6.0, it takes very little messing around to cause OpenAL to do horrible things. It should now be much more stable, and you *should* be able to play/stop/pause/resume/rewind/loop like a madman without disasters. Seek and tell, however, are still not tested and verified for all decoders, but that's less important. Also, all objects now have object:type() and object:typeOf(), which returns the type name of the object, and checks whether an object is of a certain type, respectively.
This commit is contained in:
@@ -40,7 +40,7 @@ namespace sound
|
||||
* Indicates how many bytes of raw data should be generated at each
|
||||
* call to Decode.
|
||||
**/
|
||||
static const int DEFAULT_BUFFER_SIZE = 1024;
|
||||
static const int DEFAULT_BUFFER_SIZE = 2048;
|
||||
|
||||
/**
|
||||
* Indicates the quality of the sound.
|
||||
@@ -55,7 +55,7 @@ namespace sound
|
||||
/**
|
||||
* 16 bit audio is the default.
|
||||
**/
|
||||
static const int DEFAULT_T = 16;
|
||||
static const int DEFAULT_BITS = 16;
|
||||
|
||||
/**
|
||||
* Creates a deep of itself. The sound stream can (and should) be
|
||||
|
||||
@@ -60,7 +60,11 @@ namespace lullaby
|
||||
bool ModPlugDecoder::accepts(const std::string & ext)
|
||||
{
|
||||
static const std::string supported[] = {
|
||||
"it", "xm", "mod", "wav", ""
|
||||
"699", "abc", "amf", "ams", "dbm", "dmf",
|
||||
"dsm", "far", "it", "j2b", "mdl", "med",
|
||||
"mid", "mod", "mt2", "mtm", "okt", "pat",
|
||||
"psm", "s3m", "stm", "ult", "umx", "wav",
|
||||
"xm", ""
|
||||
};
|
||||
|
||||
for(int i = 0; !(supported[i].empty()); i++)
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace lullaby
|
||||
public:
|
||||
|
||||
ModPlugDecoder(Data * data, const std::string & ext, int bufferSize, int sampleRate);
|
||||
~ModPlugDecoder();
|
||||
virtual ~ModPlugDecoder();
|
||||
|
||||
static bool accepts(const std::string & ext);
|
||||
|
||||
|
||||
@@ -34,9 +34,12 @@ namespace lullaby
|
||||
bool Mpg123Decoder::inited = false;
|
||||
|
||||
Mpg123Decoder::Mpg123Decoder(Data * data, const std::string & ext, int bufferSize, int sampleRate)
|
||||
: Decoder(data, ext, bufferSize, sampleRate), handle(0), islooping(false)
|
||||
: Decoder(data, ext, bufferSize, sampleRate), handle(0)
|
||||
{
|
||||
|
||||
data_size = data->getSize();
|
||||
data_offset = 0;
|
||||
|
||||
int ret;
|
||||
|
||||
if(!inited)
|
||||
@@ -57,21 +60,11 @@ namespace lullaby
|
||||
ret = mpg123_format(handle, sampleRate, MPG123_STEREO, MPG123_ENC_SIGNED_16);
|
||||
if (ret != MPG123_OK)
|
||||
throw love::Exception("Could not set output format.");
|
||||
size_t numbytes = 0;
|
||||
ret = mpg123_decode(handle, (unsigned char*)data->getData(), data->getSize(), NULL, 0, &numbytes);
|
||||
|
||||
if(ret == MPG123_NEW_FORMAT)
|
||||
{
|
||||
long rate;
|
||||
int channels;
|
||||
int encoding;
|
||||
mpg123_getformat(handle, &rate, &channels, &encoding);
|
||||
}
|
||||
else if(ret != 0)
|
||||
{
|
||||
throw love::Exception(mpg123_strerror(handle));
|
||||
}
|
||||
|
||||
ret = feed(16384);
|
||||
|
||||
if (ret != MPG123_OK && ret != MPG123_DONE)
|
||||
throw love::Exception("Could not feed!");
|
||||
}
|
||||
|
||||
Mpg123Decoder::~Mpg123Decoder()
|
||||
@@ -108,26 +101,51 @@ namespace lullaby
|
||||
|
||||
int Mpg123Decoder::decode()
|
||||
{
|
||||
size_t numbytes;
|
||||
int r = mpg123_read(handle, (unsigned char*) buffer, bufferSize, &numbytes);
|
||||
|
||||
if (r == MPG123_DONE || r != MPG123_OK)
|
||||
int size = 0;
|
||||
bool done = false;
|
||||
|
||||
while(size < bufferSize && !done && !eof)
|
||||
{
|
||||
if ( r == MPG123_NEED_MORE && islooping )
|
||||
{
|
||||
islooping = false;
|
||||
size_t numbytes = 0;
|
||||
mpg123_decode(handle, (unsigned char*) data->getData(), data->getSize(), (unsigned char*) buffer, bufferSize, &numbytes);
|
||||
}
|
||||
else
|
||||
size_t numbytes = 0;
|
||||
|
||||
int r = mpg123_read(handle, (unsigned char*) buffer + size, bufferSize - size, &numbytes);
|
||||
|
||||
switch(r)
|
||||
{
|
||||
case MPG123_NEW_FORMAT:
|
||||
continue;
|
||||
case MPG123_NEED_MORE:
|
||||
{
|
||||
int v = feed(8192);
|
||||
|
||||
switch(v)
|
||||
{
|
||||
case MPG123_OK:
|
||||
continue;
|
||||
case MPG123_DONE:
|
||||
if(numbytes == 0)
|
||||
eof = true;
|
||||
break;
|
||||
default:
|
||||
done = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
case MPG123_OK:
|
||||
size += numbytes;
|
||||
continue;
|
||||
case MPG123_DONE:
|
||||
// Apparently, mpg123_read does not return MPG123_DONE, but
|
||||
// let's keep it here anyway.
|
||||
eof = true;
|
||||
numbytes = 0;
|
||||
default:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return numbytes;
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Mpg123Decoder::seek(float s)
|
||||
@@ -139,11 +157,16 @@ namespace lullaby
|
||||
|
||||
bool Mpg123Decoder::rewind()
|
||||
{
|
||||
if(mpg123_seek(handle, 0, SEEK_SET) >= 0)
|
||||
return false;
|
||||
islooping = true;
|
||||
eof = false;
|
||||
return true;
|
||||
off_t offset;
|
||||
|
||||
if(mpg123_feedseek(handle, 0, SEEK_SET, &offset) >= 0)
|
||||
{
|
||||
data_offset = offset;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Mpg123Decoder::isSeekable()
|
||||
@@ -160,7 +183,23 @@ namespace lullaby
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
int Mpg123Decoder::feed(int bytes)
|
||||
{
|
||||
int remaining = data_size - data_offset;
|
||||
|
||||
if(remaining <= 0)
|
||||
return MPG123_DONE;
|
||||
|
||||
int feed_bytes = remaining < bytes ? remaining : bytes;
|
||||
|
||||
int r = mpg123_feed(handle, (unsigned char*)data->getData() + data_offset, feed_bytes);
|
||||
|
||||
if(r == MPG123_OK || r == MPG123_DONE)
|
||||
data_offset += feed_bytes;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
} // lullaby
|
||||
} // sound
|
||||
|
||||
@@ -43,13 +43,15 @@ namespace lullaby
|
||||
private:
|
||||
|
||||
mpg123_handle * handle;
|
||||
bool islooping;
|
||||
static bool inited;
|
||||
|
||||
int data_offset;
|
||||
int data_size;
|
||||
|
||||
public:
|
||||
|
||||
Mpg123Decoder(Data * data, const std::string & ext, int bufferSize, int sampleRate);
|
||||
~Mpg123Decoder();
|
||||
virtual ~Mpg123Decoder();
|
||||
|
||||
static bool accepts(const std::string & ext);
|
||||
static void quit();
|
||||
@@ -62,6 +64,10 @@ namespace lullaby
|
||||
int getChannels() const;
|
||||
int getBits() const;
|
||||
|
||||
private:
|
||||
|
||||
int feed(int bytes);
|
||||
|
||||
}; // Decoder
|
||||
|
||||
} // lullaby
|
||||
|
||||
@@ -55,9 +55,9 @@ namespace lullaby
|
||||
// Find a suitable decoder here, and return it.
|
||||
if(ModPlugDecoder::accepts(ext))
|
||||
decoder = new ModPlugDecoder(data, ext, bufferSize, sampleRate);
|
||||
else if (Mpg123Decoder::accepts(ext))
|
||||
else if(Mpg123Decoder::accepts(ext))
|
||||
decoder = new Mpg123Decoder(data, ext, bufferSize, sampleRate);
|
||||
else if (VorbisDecoder::accepts(ext))
|
||||
else if(VorbisDecoder::accepts(ext))
|
||||
decoder = new VorbisDecoder(data, ext, bufferSize, sampleRate);
|
||||
/*else if (FLACDecoder::accepts(ext))
|
||||
decoder = new FLACDecoder(data, ext, bufferSize, sampleRate);*/
|
||||
|
||||
@@ -182,42 +182,20 @@ namespace lullaby
|
||||
|
||||
int VorbisDecoder::decode()
|
||||
{
|
||||
int bits = this->getBits();
|
||||
int size = 0;
|
||||
int section;
|
||||
int result;
|
||||
|
||||
if(bits == 16)
|
||||
bits = 2;
|
||||
else
|
||||
bits = 1;
|
||||
|
||||
while(size < bufferSize)
|
||||
{
|
||||
result = ov_read(&handle, (char*) buffer + size, bufferSize - size, endian, bits, 1, §ion);
|
||||
int result = ov_read(&handle, (char*) buffer + size, bufferSize - size, endian, (getBits() == 16 ? 2 : 1), 1, 0);
|
||||
|
||||
if(result > 0)
|
||||
size += result;
|
||||
else if(result < 0)
|
||||
{
|
||||
switch(result)
|
||||
{
|
||||
case OV_EREAD:
|
||||
throw love::Exception("Vorbis read: Read from media");
|
||||
case OV_ENOTVORBIS:
|
||||
throw love::Exception("Vorbis read: Not Vorbis data");
|
||||
case OV_EVERSION:
|
||||
throw love::Exception("Vorbis read: Vorbis version mismatch");
|
||||
case OV_EBADHEADER:
|
||||
throw love::Exception("Vorbis read: Invalid Vorbis header");
|
||||
case OV_EFAULT:
|
||||
throw love::Exception("Vorbis read: Internal logic fault (bug or heap/stack corruption)");
|
||||
default:
|
||||
throw love::Exception("Vorbis read: Unknown error");
|
||||
}
|
||||
}
|
||||
else
|
||||
if(result == OV_HOLE)
|
||||
continue;
|
||||
else if(result <= OV_EREAD)
|
||||
return -1;
|
||||
else if(result == 0)
|
||||
break;
|
||||
else if(result > 0)
|
||||
size += result;
|
||||
}
|
||||
|
||||
if(oggFile.dataSize - oggFile.dataRead == 0)
|
||||
@@ -256,7 +234,8 @@ namespace lullaby
|
||||
bool VorbisDecoder::rewind()
|
||||
{
|
||||
eof = false;
|
||||
return this->seek(0);
|
||||
ov_pcm_seek(&handle, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VorbisDecoder::isSeekable()
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace lullaby
|
||||
public:
|
||||
|
||||
VorbisDecoder(Data * data, const std::string & ext, int bufferSize, int sampleRate);
|
||||
~VorbisDecoder();
|
||||
virtual ~VorbisDecoder();
|
||||
|
||||
static bool accepts(const std::string & ext);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace sound
|
||||
{
|
||||
int samples = luaL_checkint(L, 1);
|
||||
int sampleRate = luaL_optint(L, 2, Decoder::DEFAULT_SAMPLE_RATE);
|
||||
int bits = luaL_optint(L, 3, Decoder::DEFAULT_T);
|
||||
int bits = luaL_optint(L, 3, Decoder::DEFAULT_BITS);
|
||||
int channels = luaL_optint(L, 4, Decoder::DEFAULT_CHANNELS);
|
||||
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user