Browse Source

Merge pull request #1627 from MikuAuahDark/sounddata-copyfrom

SoundData:copyFrom() and SoundData:slice()
Alex Szpakowski 4 years ago
parent
commit
dcf0968f05

+ 44 - 2
src/modules/sound/SoundData.cpp

@@ -98,7 +98,7 @@ SoundData::SoundData(int samples, int sampleRate, int bitDepth, int channels)
 	load(samples, sampleRate, bitDepth, channels);
 }
 
-SoundData::SoundData(void *d, int samples, int sampleRate, int bitDepth, int channels)
+SoundData::SoundData(const void *d, int samples, int sampleRate, int bitDepth, int channels)
 	: data(0)
 	, size(0)
 	, sampleRate(0)
@@ -129,7 +129,7 @@ SoundData *SoundData::clone() const
 	return new SoundData(*this);
 }
 
-void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, void *newData)
+void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, const void *newData)
 {
 	if (samples <= 0)
 		throw love::Exception("Invalid sample count: %d", samples);
@@ -258,5 +258,47 @@ float SoundData::getSample(int i, int channel) const
 	return getSample(i * channels + (channel - 1));
 }
 
+void SoundData::copyFrom(const SoundData *src, int srcStart, int count, int dstStart)
+{
+	if (channels != src->channels)
+		throw love::Exception("Channel count mismatch!");
+
+	size_t bytesPerSample = (size_t) channels * bitDepth/8;
+	size_t srcBytesPerSample = (size_t) src->channels * src->bitDepth/8;
+	
+	// Check range
+	if (dstStart < 0 || (dstStart+count) * bytesPerSample > size)
+		throw love::Exception("Destination out-of-range!");
+	if (srcStart < 0 || (srcStart+count) * srcBytesPerSample > src->size)
+		throw love::Exception("Source out-of-range!");
+
+	if (bitDepth != src->bitDepth)
+	{
+		// Bit depth mismatch, use get/setSample at loop
+		for (int i = 0; i < count * channels; i++)
+			setSample(dstStart * channels + i, src->getSample(srcStart * channels + i));
+	}
+	else if (this->data == src->data)
+		// May overlap, use memmove
+		memmove(data + dstStart * bytesPerSample, src->data + srcStart * bytesPerSample, count * bytesPerSample);
+	else
+		memcpy(data + dstStart * bytesPerSample, src->data + srcStart * bytesPerSample, count * bytesPerSample);
+}
+
+SoundData *SoundData::slice(int start, int length) const
+{
+	int totalSamples = getSampleCount();
+
+	if (length == 0)
+		throw love::Exception("Invalid slice length: 0");
+	else if (length < 0)
+		length = totalSamples - start;
+
+	if (start < 0 || start + length > totalSamples)
+		throw love::Exception("Attempt to slice at out-of-range position!");
+
+	return new SoundData(data + start * channels * bitDepth/8, length, sampleRate, bitDepth, channels);
+}
+
 } // sound
 } // love

+ 5 - 2
src/modules/sound/SoundData.h

@@ -39,7 +39,7 @@ public:
 
 	SoundData(Decoder *decoder);
 	SoundData(int samples, int sampleRate, int bitDepth, int channels);
-	SoundData(void *d, int samples, int sampleRate, int bitDepth, int channels);
+	SoundData(const void *d, int samples, int sampleRate, int bitDepth, int channels);
 	SoundData(const SoundData &c);
 
 	virtual ~SoundData();
@@ -61,9 +61,12 @@ public:
 	float getSample(int i) const;
 	float getSample(int i, int channel) const;
 
+	void copyFrom(const SoundData *src, int srcStart, int count, int dstStart);
+	SoundData *slice(int start, int length = -1) const;
+
 private:
 
-	void load(int samples, int sampleRate, int bitDepth, int channels, void *newData = 0);
+	void load(int samples, int sampleRate, int bitDepth, int channels, const void *newData = 0);
 
 	uint8 *data;
 	size_t size;

+ 27 - 0
src/modules/sound/wrap_SoundData.cpp

@@ -121,6 +121,31 @@ int w_SoundData_getSample(lua_State *L)
 	return 1;
 }
 
+int w_SoundData_copyFrom(lua_State *L)
+{
+	SoundData *dst = luax_checksounddata(L, 1);
+	const SoundData *src = luax_checksounddata(L, 2);
+
+	int srcStart = (int) luaL_checkinteger(L, 3);
+	int count = (int) luaL_checkinteger(L, 4);
+	int dstStart = (int) luaL_optinteger(L, 5, 0);
+
+	luax_catchexcept(L, [&](){ dst->copyFrom(src, srcStart, count, dstStart); });
+	return 0;
+}
+
+int w_SoundData_slice(lua_State *L)
+{
+	SoundData *t = luax_checksounddata(L, 1), *c = nullptr;
+	int start = (int) luaL_checkinteger(L, 2);
+	int length = (int) luaL_optinteger(L, 3, -1);
+
+	luax_catchexcept(L, [&](){ c = t->slice(start, length); });
+	luax_pushtype(L, c);
+	c->release();
+	return 1;
+}
+
 static const luaL_Reg w_SoundData_functions[] =
 {
 	{ "clone", w_SoundData_clone },
@@ -131,6 +156,8 @@ static const luaL_Reg w_SoundData_functions[] =
 	{ "getDuration", w_SoundData_getDuration },
 	{ "setSample", w_SoundData_setSample },
 	{ "getSample", w_SoundData_getSample },
+	{ "copyFrom", w_SoundData_copyFrom },
+	{ "slice", w_SoundData_slice },
 
 	{ 0, 0 }
 };