mirror of
https://github.com/love2d/love-android.git
synced 2026-08-21 05:00:22 +02:00
Using latest android branch of LÖVE (6d14516b05c9) that now syncs with default (woooo!)
This commit is contained in:
@@ -41,6 +41,9 @@ SoundData::SoundData(Decoder *decoder)
|
||||
, bitDepth(0)
|
||||
, channels(0)
|
||||
{
|
||||
if (decoder->getBitDepth() != 8 && decoder->getBitDepth() != 16)
|
||||
throw love::Exception("Invalid bit depth: %d", decoder->getBitDepth());
|
||||
|
||||
size_t bufferSize = 524288; // 0x80000
|
||||
int decoded = decoder->decode();
|
||||
|
||||
@@ -117,7 +120,7 @@ void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, vo
|
||||
if (sampleRate <= 0)
|
||||
throw love::Exception("Invalid sample rate: %d", sampleRate);
|
||||
|
||||
if (bitDepth <= 0)
|
||||
if (bitDepth != 8 && bitDepth != 16)
|
||||
throw love::Exception("Invalid bit depth: %d", bitDepth);
|
||||
|
||||
if (channels <= 0)
|
||||
@@ -176,7 +179,7 @@ int SoundData::getSampleRate() const
|
||||
|
||||
int SoundData::getSampleCount() const
|
||||
{
|
||||
return (size/channels)/(bitDepth/8);
|
||||
return (int) ((size/channels)/(bitDepth/8));
|
||||
}
|
||||
|
||||
float SoundData::getDuration() const
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifdef LOVE_SUPPORT_COREAUDIO
|
||||
|
||||
// LOVE
|
||||
#include "CoreAudioDecoder.h"
|
||||
|
||||
// C++
|
||||
#include <vector>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
{
|
||||
namespace lullaby
|
||||
{
|
||||
|
||||
// Callbacks
|
||||
namespace
|
||||
{
|
||||
OSStatus readFunc(void *inClientData, SInt64 inPosition, UInt32 requestCount, void *buffer, UInt32 *actualCount)
|
||||
{
|
||||
Data *data = (Data *) inClientData;
|
||||
SInt64 bytesLeft = data->getSize() - inPosition;
|
||||
|
||||
if (bytesLeft > 0)
|
||||
{
|
||||
UInt32 actualSize = bytesLeft >= requestCount ? requestCount : (UInt32) bytesLeft;
|
||||
memcpy(buffer, (char *) data->getData() + inPosition, actualSize);
|
||||
*actualCount = actualSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
*actualCount = 0;
|
||||
return kAudioFilePositionError;
|
||||
}
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
||||
SInt64 getSizeFunc(void *inClientData)
|
||||
{
|
||||
Data *data = (Data *) inClientData;
|
||||
return data->getSize();
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
CoreAudioDecoder::CoreAudioDecoder(Data *data, const std::string &ext, int bufferSize)
|
||||
: Decoder(data, ext, bufferSize)
|
||||
, audioFile(nullptr)
|
||||
, extAudioFile(nullptr)
|
||||
, inputInfo()
|
||||
, outputInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
OSStatus err = noErr;
|
||||
|
||||
// Open the file represented by the Data.
|
||||
err = AudioFileOpenWithCallbacks(data, readFunc, nullptr, getSizeFunc, nullptr, kAudioFileMP3Type, &audioFile);
|
||||
if (err != noErr)
|
||||
throw love::Exception("Could open audio file for decoding.");
|
||||
|
||||
// We want to use the Extended AudioFile API.
|
||||
err = ExtAudioFileWrapAudioFileID(audioFile, false, &extAudioFile);
|
||||
|
||||
if (err != noErr)
|
||||
throw love::Exception("Could open audio file for decoding.");
|
||||
|
||||
// Get the format of the audio data.
|
||||
UInt32 propertySize = sizeof(inputInfo);
|
||||
err = ExtAudioFileGetProperty(extAudioFile, kExtAudioFileProperty_FileDataFormat, &propertySize, &inputInfo);
|
||||
|
||||
if (err != noErr)
|
||||
throw love::Exception("Could not determine file format.");
|
||||
|
||||
// Set the output format to 16 bit signed integer (native-endian) data.
|
||||
// Keep the channel count and sample rate of the source format.
|
||||
outputInfo.mSampleRate = inputInfo.mSampleRate;
|
||||
outputInfo.mChannelsPerFrame = inputInfo.mChannelsPerFrame;
|
||||
|
||||
int bytes = (inputInfo.mBitsPerChannel == 8) ? 1 : 2;
|
||||
|
||||
outputInfo.mFormatID = kAudioFormatLinearPCM;
|
||||
outputInfo.mBitsPerChannel = bytes * 8;
|
||||
outputInfo.mBytesPerFrame = bytes * outputInfo.mChannelsPerFrame;
|
||||
outputInfo.mFramesPerPacket = 1;
|
||||
outputInfo.mBytesPerPacket = bytes * outputInfo.mChannelsPerFrame;
|
||||
outputInfo.mFormatFlags = kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked;
|
||||
|
||||
// unsigned 8-bit or signed 16-bit integer PCM data.
|
||||
if (outputInfo.mBitsPerChannel == 16)
|
||||
outputInfo.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
|
||||
|
||||
// Set the desired output format.
|
||||
propertySize = sizeof(outputInfo);
|
||||
err = ExtAudioFileSetProperty(extAudioFile, kExtAudioFileProperty_ClientDataFormat, propertySize, &outputInfo);
|
||||
|
||||
if (err != noErr)
|
||||
throw love::Exception("Could not set decoder properties.");
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
closeAudioFile();
|
||||
throw;
|
||||
}
|
||||
|
||||
sampleRate = (int) outputInfo.mSampleRate;
|
||||
}
|
||||
|
||||
CoreAudioDecoder::~CoreAudioDecoder()
|
||||
{
|
||||
closeAudioFile();
|
||||
}
|
||||
|
||||
void CoreAudioDecoder::closeAudioFile()
|
||||
{
|
||||
if (extAudioFile != nullptr)
|
||||
ExtAudioFileDispose(extAudioFile);
|
||||
else if (audioFile != nullptr)
|
||||
AudioFileClose(audioFile);
|
||||
|
||||
extAudioFile = nullptr;
|
||||
audioFile = nullptr;
|
||||
}
|
||||
|
||||
bool CoreAudioDecoder::accepts(const std::string &ext)
|
||||
{
|
||||
UInt32 size = 0;
|
||||
std::vector<UInt32> types;
|
||||
|
||||
// Get the size in bytes of the type array we're about to get.
|
||||
OSStatus err = AudioFileGetGlobalInfoSize(kAudioFileGlobalInfo_ReadableTypes, sizeof(UInt32), nullptr, &size);
|
||||
if (err != noErr)
|
||||
return false;
|
||||
|
||||
types.resize(size / sizeof(UInt32));
|
||||
|
||||
// Get an array of supported types.
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ReadableTypes, 0, nullptr, &size, &types[0]);
|
||||
if (err != noErr)
|
||||
return false;
|
||||
|
||||
// Turn the extension string into a CFStringRef.
|
||||
CFStringRef extstr = CFStringCreateWithCString(nullptr, ext.c_str(), kCFStringEncodingUTF8);
|
||||
|
||||
CFArrayRef exts = nullptr;
|
||||
size = sizeof(CFArrayRef);
|
||||
|
||||
for (UInt32 type : types)
|
||||
{
|
||||
// Get the extension strings for the type.
|
||||
err = AudioFileGetGlobalInfo(kAudioFileGlobalInfo_ExtensionsForType, sizeof(UInt32), &type, &size, &exts);
|
||||
if (err != noErr)
|
||||
continue;
|
||||
|
||||
// A type can have more than one extension string.
|
||||
for (CFIndex i = 0; i < CFArrayGetCount(exts); i++)
|
||||
{
|
||||
CFStringRef value = (CFStringRef) CFArrayGetValueAtIndex(exts, i);
|
||||
|
||||
if (CFStringCompare(extstr, value, 0) == kCFCompareEqualTo)
|
||||
{
|
||||
CFRelease(extstr);
|
||||
CFRelease(exts);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(exts);
|
||||
}
|
||||
|
||||
CFRelease(extstr);
|
||||
return false;
|
||||
}
|
||||
|
||||
love::sound::Decoder *CoreAudioDecoder::clone()
|
||||
{
|
||||
return new CoreAudioDecoder(data.get(), ext, bufferSize);
|
||||
}
|
||||
|
||||
int CoreAudioDecoder::decode()
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
while (size < bufferSize)
|
||||
{
|
||||
AudioBufferList dataBuffer;
|
||||
dataBuffer.mNumberBuffers = 1;
|
||||
dataBuffer.mBuffers[0].mDataByteSize = bufferSize - size;
|
||||
dataBuffer.mBuffers[0].mData = (char *) buffer + size;
|
||||
dataBuffer.mBuffers[0].mNumberChannels = outputInfo.mChannelsPerFrame;
|
||||
|
||||
UInt32 frames = (bufferSize - size) / outputInfo.mBytesPerFrame;
|
||||
|
||||
if (ExtAudioFileRead(extAudioFile, &frames, &dataBuffer) != noErr)
|
||||
return size;
|
||||
|
||||
if (frames == 0)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
|
||||
size += frames * outputInfo.mBytesPerFrame;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
bool CoreAudioDecoder::seek(float s)
|
||||
{
|
||||
OSStatus err = ExtAudioFileSeek(extAudioFile, (SInt64) (s * inputInfo.mSampleRate));
|
||||
|
||||
if (err == noErr)
|
||||
{
|
||||
eof = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoreAudioDecoder::rewind()
|
||||
{
|
||||
OSStatus err = ExtAudioFileSeek(extAudioFile, 0);
|
||||
|
||||
if (err == noErr)
|
||||
{
|
||||
eof = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CoreAudioDecoder::isSeekable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int CoreAudioDecoder::getChannels() const
|
||||
{
|
||||
return outputInfo.mChannelsPerFrame;
|
||||
}
|
||||
|
||||
int CoreAudioDecoder::getBitDepth() const
|
||||
{
|
||||
return outputInfo.mBitsPerChannel;
|
||||
}
|
||||
|
||||
} // lullaby
|
||||
} // sound
|
||||
} // love
|
||||
|
||||
#endif // LOVE_SUPPORT_COREAUDIO
|
||||
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* 1. The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* 2. Altered source versions must be plainly marked as such, and must not be
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
|
||||
#ifndef LOVE_SOUND_LULLABY_CORE_AUDIO_DECODER_H
|
||||
#define LOVE_SOUND_LULLABY_CORE_AUDIO_DECODER_H
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
#ifdef LOVE_SUPPORT_COREAUDIO
|
||||
|
||||
// LOVE
|
||||
#include "common/Data.h"
|
||||
#include "Decoder.h"
|
||||
|
||||
// Core Audio
|
||||
#include <AudioToolbox/AudioFormat.h>
|
||||
#include <AudioToolbox/ExtendedAudioFile.h>
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
{
|
||||
namespace lullaby
|
||||
{
|
||||
|
||||
/**
|
||||
* Decoder which supports all formats handled by Apple's Core Audio framework.
|
||||
**/
|
||||
class CoreAudioDecoder : public Decoder
|
||||
{
|
||||
public:
|
||||
|
||||
CoreAudioDecoder(Data *data, const std::string &ext, int bufferSize);
|
||||
virtual ~CoreAudioDecoder();
|
||||
|
||||
static bool accepts(const std::string &ext);
|
||||
|
||||
love::sound::Decoder *clone();
|
||||
int decode();
|
||||
bool seek(float s);
|
||||
bool rewind();
|
||||
bool isSeekable();
|
||||
int getChannels() const;
|
||||
int getBitDepth() const;
|
||||
|
||||
private:
|
||||
|
||||
void closeAudioFile();
|
||||
|
||||
AudioFileID audioFile;
|
||||
ExtAudioFileRef extAudioFile;
|
||||
|
||||
AudioStreamBasicDescription inputInfo;
|
||||
AudioStreamBasicDescription outputInfo;
|
||||
|
||||
}; // CoreAudioDecoder
|
||||
|
||||
} // lullaby
|
||||
} // sound
|
||||
} // love
|
||||
|
||||
#endif // LOVE_SUPPORT_COREAUDIO
|
||||
|
||||
#endif // LOVE_SOUND_LULLABY_CORE_AUDIO_DECODER_H
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "common/Data.h"
|
||||
#include "Decoder.h"
|
||||
|
||||
#ifdef LOVE_MACOSX_USE_FRAMEWORKS
|
||||
#ifdef LOVE_APPLE_USE_FRAMEWORKS
|
||||
#include <Game_Music_Emu/gme.h>
|
||||
#else
|
||||
#include <gme.h>
|
||||
|
||||
@@ -17,9 +17,11 @@
|
||||
* misrepresented as being the original software.
|
||||
* 3. This notice may not be removed or altered from any source distribution.
|
||||
**/
|
||||
#include "common/config.h"
|
||||
|
||||
#include "ModPlugDecoder.h"
|
||||
|
||||
#ifndef LOVE_NO_MODPLUG
|
||||
|
||||
#include "common/Exception.h"
|
||||
|
||||
namespace love
|
||||
@@ -45,11 +47,8 @@ ModPlugDecoder::ModPlugDecoder(Data *data, const std::string &ext, int bufferSiz
|
||||
// garbage settings when the struct is only partially initialized)
|
||||
// This does not exist yet on Windows.
|
||||
|
||||
// Some settings not supported by some older versions
|
||||
#ifndef LOVE_OLD_MODPLUG
|
||||
settings.mStereoSeparation = 128;
|
||||
settings.mMaxMixChannels = 32;
|
||||
#endif
|
||||
settings.mReverbDepth = 0;
|
||||
settings.mReverbDelay = 0;
|
||||
settings.mBassAmount = 0;
|
||||
@@ -145,3 +144,5 @@ int ModPlugDecoder::getBitDepth() const
|
||||
} // lullaby
|
||||
} // sound
|
||||
} // love
|
||||
|
||||
#endif // LOVE_NO_MODPLUG
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#ifndef LOVE_SOUND_LULLABY_MODPLUG_DECODER_H
|
||||
#define LOVE_SOUND_LULLABY_MODPLUG_DECODER_H
|
||||
|
||||
#include "common/config.h"
|
||||
|
||||
#ifndef LOVE_NO_MODPLUG
|
||||
|
||||
// LOVE
|
||||
#include "common/Data.h"
|
||||
#include "Decoder.h"
|
||||
@@ -62,4 +66,6 @@ private:
|
||||
} // sound
|
||||
} // love
|
||||
|
||||
#endif // LOVE_NO_MODPLUG
|
||||
|
||||
#endif // LOVE_SOUND_LULLABY_MODPLUG_DECODER_H
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "Decoder.h"
|
||||
|
||||
// libmpg123
|
||||
#ifdef LOVE_MACOSX_USE_FRAMEWORKS
|
||||
#ifdef LOVE_APPLE_USE_FRAMEWORKS
|
||||
#include <mpg123/mpg123.h>
|
||||
#else
|
||||
#include <mpg123.h>
|
||||
|
||||
@@ -34,6 +34,10 @@
|
||||
# include "Mpg123Decoder.h"
|
||||
#endif // LOVE_NOMPG123
|
||||
|
||||
#ifdef LOVE_SUPPORT_COREAUDIO
|
||||
# include "CoreAudioDecoder.h"
|
||||
#endif
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
@@ -65,8 +69,12 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi
|
||||
sound::Decoder *decoder = 0;
|
||||
|
||||
// Find a suitable decoder here, and return it.
|
||||
if (ModPlugDecoder::accepts(ext))
|
||||
if (false)
|
||||
/* nothing */;
|
||||
#ifndef LOVE_NO_MODPLUG
|
||||
else if (ModPlugDecoder::accepts(ext))
|
||||
decoder = new ModPlugDecoder(data, ext, bufferSize);
|
||||
#endif // LOVE_NO_MODPLUG
|
||||
#ifndef LOVE_NOMPG123
|
||||
else if (Mpg123Decoder::accepts(ext))
|
||||
decoder = new Mpg123Decoder(data, ext, bufferSize);
|
||||
@@ -77,6 +85,10 @@ sound::Decoder *Sound::newDecoder(love::filesystem::FileData *data, int bufferSi
|
||||
else if (GmeDecoder::accepts(ext))
|
||||
decoder = new GmeDecoder(data, ext, bufferSize);
|
||||
#endif // LOVE_SUPPORT_GME
|
||||
#ifdef LOVE_SUPPORT_COREAUDIO
|
||||
else if (CoreAudioDecoder::accepts(ext))
|
||||
decoder = new CoreAudioDecoder(data, ext, bufferSize);
|
||||
#endif
|
||||
else if (WaveDecoder::accepts(ext))
|
||||
decoder = new WaveDecoder(data, ext, bufferSize);
|
||||
/*else if (FLACDecoder::accepts(ext))
|
||||
|
||||
@@ -63,7 +63,7 @@ static size_t vorbisRead(void *ptr /* ptr to the data that the vorbis files need
|
||||
if (actualSizeToRead)
|
||||
{
|
||||
// Copy the data from the start of the file PLUS how much we have already read in
|
||||
memcpy(ptr, (char *)vorbisData->dataPtr + vorbisData->dataRead, actualSizeToRead);
|
||||
memcpy(ptr, (const char *)vorbisData->dataPtr + vorbisData->dataRead, actualSizeToRead);
|
||||
// Increase by how much we have read by
|
||||
vorbisData->dataRead += (actualSizeToRead);
|
||||
}
|
||||
@@ -109,7 +109,7 @@ static int vorbisSeek(void *datasource /* ptr to the data that the vorbis files
|
||||
vorbisData->dataRead = vorbisData->dataSize+1;
|
||||
break;
|
||||
default:
|
||||
throw love::Exception("Unknown seek command in vorbisSeek\n");
|
||||
throw love::Exception("Unknown seek command in vorbisSeek");
|
||||
break;
|
||||
};
|
||||
|
||||
@@ -143,8 +143,8 @@ VorbisDecoder::VorbisDecoder(Data *data, const std::string &ext, int bufferSize)
|
||||
#endif
|
||||
|
||||
// Initialize OGG file
|
||||
oggFile.dataPtr = (char *) data->getData();
|
||||
oggFile.dataSize = data->getSize();
|
||||
oggFile.dataPtr = (const char *) data->getData();
|
||||
oggFile.dataSize = (int) data->getSize();
|
||||
oggFile.dataRead = 0;
|
||||
|
||||
// Open Vorbis handle
|
||||
@@ -188,7 +188,7 @@ int VorbisDecoder::decode()
|
||||
|
||||
while (size < bufferSize)
|
||||
{
|
||||
int result = ov_read(&handle, (char *) buffer + size, bufferSize - size, endian, (getBitDepth() == 16 ? 2 : 1), 1, 0);
|
||||
long result = ov_read(&handle, (char *) buffer + size, bufferSize - size, endian, (getBitDepth() == 16 ? 2 : 1), 1, 0);
|
||||
|
||||
if (result == OV_HOLE)
|
||||
continue;
|
||||
@@ -250,7 +250,7 @@ int VorbisDecoder::getBitDepth() const
|
||||
|
||||
int VorbisDecoder::getSampleRate() const
|
||||
{
|
||||
return vorbisInfo->rate;
|
||||
return (int) vorbisInfo->rate;
|
||||
}
|
||||
|
||||
} // lullaby
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace lullaby
|
||||
// Struct for handling data
|
||||
struct SOggFile
|
||||
{
|
||||
char *dataPtr; // Pointer to the data in memory
|
||||
const char *dataPtr; // Pointer to the data in memory
|
||||
int dataSize; // Size of the data
|
||||
int dataRead; // How much we've read so far
|
||||
};
|
||||
|
||||
@@ -126,8 +126,8 @@ int WaveDecoder::decode()
|
||||
|
||||
while (size < (size_t) bufferSize)
|
||||
{
|
||||
size_t bytes = bufferSize;
|
||||
int wuff_status = wuff_read(handle, (wuff_uint8 *) buffer, &bytes);
|
||||
size_t bytes = bufferSize-size;
|
||||
int wuff_status = wuff_read(handle, (wuff_uint8 *) buffer+size, &bytes);
|
||||
|
||||
if (wuff_status < 0)
|
||||
return 0;
|
||||
@@ -140,7 +140,7 @@ int WaveDecoder::decode()
|
||||
size += bytes;
|
||||
}
|
||||
|
||||
return size;
|
||||
return (int) size;
|
||||
}
|
||||
|
||||
bool WaveDecoder::seek(float s)
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace sound
|
||||
|
||||
Decoder *luax_checkdecoder(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<Decoder>(L, idx, "Decoder", SOUND_DECODER_T);
|
||||
return luax_checktype<Decoder>(L, idx, SOUND_DECODER_ID);
|
||||
}
|
||||
|
||||
int w_Decoder_getChannels(lua_State *L)
|
||||
@@ -61,7 +61,7 @@ static const luaL_Reg functions[] =
|
||||
|
||||
extern "C" int luaopen_decoder(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, "Decoder", functions);
|
||||
return luax_register_type(L, SOUND_DECODER_ID, functions);
|
||||
}
|
||||
|
||||
} // sound
|
||||
|
||||
@@ -38,10 +38,10 @@ int w_newSoundData(lua_State *L)
|
||||
|
||||
if (lua_isnumber(L, 1))
|
||||
{
|
||||
int samples = luaL_checkint(L, 1);
|
||||
int sampleRate = luaL_optint(L, 2, Decoder::DEFAULT_SAMPLE_RATE);
|
||||
int bitDepth = luaL_optint(L, 3, Decoder::DEFAULT_BIT_DEPTH);
|
||||
int channels = luaL_optint(L, 4, Decoder::DEFAULT_CHANNELS);
|
||||
int samples = (int) luaL_checknumber(L, 1);
|
||||
int sampleRate = (int) luaL_optnumber(L, 2, Decoder::DEFAULT_SAMPLE_RATE);
|
||||
int bitDepth = (int) luaL_optnumber(L, 3, Decoder::DEFAULT_BIT_DEPTH);
|
||||
int channels = (int) luaL_optnumber(L, 4, Decoder::DEFAULT_CHANNELS);
|
||||
|
||||
luax_catchexcept(L, [&](){ t = instance()->newSoundData(samples, sampleRate, bitDepth, channels); });
|
||||
}
|
||||
@@ -49,7 +49,7 @@ int w_newSoundData(lua_State *L)
|
||||
else
|
||||
{
|
||||
// Convert to Decoder, if necessary.
|
||||
if (!luax_istype(L, 1, SOUND_DECODER_T))
|
||||
if (!luax_istype(L, 1, SOUND_DECODER_ID))
|
||||
{
|
||||
w_newDecoder(L);
|
||||
lua_replace(L, 1);
|
||||
@@ -58,7 +58,7 @@ int w_newSoundData(lua_State *L)
|
||||
luax_catchexcept(L, [&](){ t = instance()->newSoundData(luax_checkdecoder(L, 1)); });
|
||||
}
|
||||
|
||||
luax_pushtype(L, "SoundData", SOUND_SOUND_DATA_T, t);
|
||||
luax_pushtype(L, SOUND_SOUND_DATA_ID, t);
|
||||
t->release();
|
||||
return 1;
|
||||
}
|
||||
@@ -66,18 +66,18 @@ int w_newSoundData(lua_State *L)
|
||||
int w_newDecoder(lua_State *L)
|
||||
{
|
||||
love::filesystem::FileData *data = love::filesystem::luax_getfiledata(L, 1);
|
||||
int bufferSize = luaL_optint(L, 2, Decoder::DEFAULT_BUFFER_SIZE);
|
||||
int bufferSize = (int) luaL_optnumber(L, 2, Decoder::DEFAULT_BUFFER_SIZE);
|
||||
|
||||
Decoder *t = nullptr;
|
||||
luax_catchexcept(L,
|
||||
[&]() { t = instance()->newDecoder(data, bufferSize); },
|
||||
[&]() { data->release(); }
|
||||
[&](bool) { data->release(); }
|
||||
);
|
||||
|
||||
if (t == nullptr)
|
||||
return luaL_error(L, "Extension \"%s\" not supported.", data->getExtension().c_str());
|
||||
|
||||
luax_pushtype(L, "Decoder", SOUND_DECODER_T, t);
|
||||
luax_pushtype(L, SOUND_DECODER_ID, t);
|
||||
t->release();
|
||||
return 1;
|
||||
}
|
||||
@@ -111,7 +111,7 @@ extern "C" int luaopen_love_sound(lua_State *L)
|
||||
WrappedModule w;
|
||||
w.module = instance;
|
||||
w.name = "sound";
|
||||
w.flags = MODULE_SOUND_T;
|
||||
w.type = MODULE_SOUND_ID;
|
||||
w.functions = functions;
|
||||
w.types = types;
|
||||
|
||||
|
||||
@@ -22,14 +22,24 @@
|
||||
|
||||
#include "common/wrap_Data.h"
|
||||
|
||||
// Shove the wrap_SoundData.lua code directly into a raw string literal.
|
||||
static const char sounddata_lua[] =
|
||||
#include "wrap_SoundData.lua"
|
||||
;
|
||||
|
||||
namespace love
|
||||
{
|
||||
namespace sound
|
||||
{
|
||||
|
||||
/**
|
||||
* NOTE: Additional wrapper code is in wrap_SoundData.lua. Be sure to keep it
|
||||
* in sync with any changes made to this file!
|
||||
**/
|
||||
|
||||
SoundData *luax_checksounddata(lua_State *L, int idx)
|
||||
{
|
||||
return luax_checktype<SoundData>(L, idx, "SoundData", SOUND_SOUND_DATA_T);
|
||||
return luax_checktype<SoundData>(L, idx, SOUND_SOUND_DATA_ID);
|
||||
}
|
||||
|
||||
int w_SoundData_getChannels(lua_State *L)
|
||||
@@ -105,7 +115,22 @@ static const luaL_Reg functions[] =
|
||||
|
||||
extern "C" int luaopen_sounddata(lua_State *L)
|
||||
{
|
||||
return luax_register_type(L, "SoundData", functions);
|
||||
// The last argument pushes the type's metatable onto the stack.
|
||||
int ret = luax_register_type(L, SOUND_SOUND_DATA_ID, functions, true);
|
||||
|
||||
// Load and execute SoundData.lua, sending the metatable as an argument.
|
||||
if (ret > 0)
|
||||
{
|
||||
luaL_loadbuffer(L, sounddata_lua, sizeof(sounddata_lua), "SoundData.lua");
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 0);
|
||||
|
||||
// Pop the metatable.
|
||||
lua_pop(L, 1);
|
||||
ret--;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // sound
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
R"luastring"--(
|
||||
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
|
||||
-- There is a matching delimiter at the bottom of the file.
|
||||
|
||||
--[[
|
||||
Copyright (c) 2006-2015 LOVE Development Team
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
--]]
|
||||
|
||||
local SoundData_mt = ...
|
||||
|
||||
if type(jit) ~= "table" or not jit.status() then
|
||||
-- LuaJIT's FFI is *much* slower than LOVE's regular methods when the JIT
|
||||
-- compiler is disabled.
|
||||
return
|
||||
end
|
||||
|
||||
local status, ffi = pcall(require, "ffi")
|
||||
if not status then return end
|
||||
|
||||
local tonumber, assert = tonumber, assert
|
||||
|
||||
local float = ffi.typeof("float")
|
||||
local datatypes = {ffi.typeof("uint8_t *"), ffi.typeof("int16_t *")}
|
||||
|
||||
local typemaxvals = {0x7F, 0x7FFF}
|
||||
|
||||
local _getBitDepth = SoundData_mt.__index.getBitDepth
|
||||
local _getSampleCount = SoundData_mt.__index.getSampleCount
|
||||
local _getSampleRate = SoundData_mt.__index.getSampleRate
|
||||
local _getChannels = SoundData_mt.__index.getChannels
|
||||
local _getDuration = SoundData_mt.__index.getDuration
|
||||
|
||||
-- Table which holds SoundData objects as keys, and information about the objects
|
||||
-- as values. Uses weak keys so the SoundData objects can still be GC'd properly.
|
||||
local objectcache = setmetatable({}, {
|
||||
__mode = "k",
|
||||
__index = function(self, sounddata)
|
||||
local bytedepth = _getBitDepth(sounddata) / 8
|
||||
local pointer = ffi.cast(datatypes[bytedepth], sounddata:getPointer())
|
||||
|
||||
local p = {
|
||||
bytedepth = bytedepth,
|
||||
pointer = pointer,
|
||||
size = sounddata:getSize(),
|
||||
maxvalue = typemaxvals[bytedepth],
|
||||
samplecount = _getSampleCount(sounddata),
|
||||
samplerate = _getSampleRate(sounddata),
|
||||
channels = _getChannels(sounddata),
|
||||
duration = _getDuration(sounddata),
|
||||
}
|
||||
|
||||
self[sounddata] = p
|
||||
return p
|
||||
end,
|
||||
})
|
||||
|
||||
|
||||
-- Overwrite existing functions with new FFI versions.
|
||||
|
||||
function SoundData_mt.__index:getSample(i)
|
||||
local p = objectcache[self]
|
||||
assert(i >= 0 and i < p.size/p.bytedepth, "Attempt to get out-of-range sample!")
|
||||
if p.bytedepth == 2 then
|
||||
-- 16-bit data is stored as signed values internally.
|
||||
return tonumber(p.pointer[i]) / p.maxvalue
|
||||
else
|
||||
-- 8-bit data is stored as unsigned values internally.
|
||||
return (tonumber(p.pointer[i]) - 128) / 127
|
||||
end
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:setSample(i, sample)
|
||||
local p = objectcache[self]
|
||||
assert(i >= 0 and i < p.size/p.bytedepth, "Attempt to set out-of-range sample!")
|
||||
if p.bytedepth == 2 then
|
||||
-- 16-bit data is stored as signed values internally.
|
||||
p.pointer[i] = sample * p.maxvalue
|
||||
else
|
||||
-- 8-bit data is stored as unsigned values internally.
|
||||
-- The float cast is needed to make values end up the same as in the
|
||||
-- C++ version of this method.
|
||||
p.pointer[i] = ffi.cast(float, (sample * 127) + 128)
|
||||
end
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:getBitDepth()
|
||||
return objectcache[self].bytedepth * 8
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:getSampleCount()
|
||||
return objectcache[self].samplecount
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:getSampleRate()
|
||||
return objectcache[self].samplerate
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:getChannels()
|
||||
return objectcache[self].channels
|
||||
end
|
||||
|
||||
function SoundData_mt.__index:getDuration()
|
||||
return objectcache[self].duration
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
Reference in New Issue
Block a user