mirror of
https://github.com/H-uru/korman.git
synced 2025-07-14 02:27:36 -04:00
Implement SoundEmit modifier
This sound emitter modifier is almost as fully functional as PlasmaMAX's various sound emitter components. Additional functionality was added to C korlib so that artists can specify OGG Vorbis sound files. If korlib is not compiled, only WAVE sounds can be utilized in Korman. This fixes some of the more fiddly bugs related to exporting to CWE that were seen in PyPRP. Sound nodes to be implemented...
This commit is contained in:
119
korlib/sound.cpp
Normal file
119
korlib/sound.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/* This file is part of Korman.
|
||||
*
|
||||
* Korman is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Korman is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Korman. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sound.h"
|
||||
|
||||
#include <PRP/Audio/plSoundBuffer.h>
|
||||
#include <Stream/hsStream.h>
|
||||
#include <vorbis/vorbisfile.h>
|
||||
|
||||
static const int BITS_PER_SAMPLE = 16;
|
||||
|
||||
extern "C" {
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
hsStream* fThis;
|
||||
bool fPyOwned;
|
||||
} pyStream;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
plWAVHeader* fThis;
|
||||
bool fPyOwned;
|
||||
} pyWAVHeader;
|
||||
|
||||
static size_t _read_stream(void* ptr, size_t size, size_t nmemb, void* datasource) {
|
||||
hsStream* s = static_cast<hsStream*>(datasource);
|
||||
// hsStream is a bit overzealous protecting us against overreads, so we need to
|
||||
// make sure to not tick it off.
|
||||
size_t request = nmemb * size;
|
||||
size_t remaining = s->size() - s->pos();
|
||||
size_t min = std::min(request, remaining);
|
||||
if (min == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
size_t read = s->read(min, ptr);
|
||||
return read / size;
|
||||
}
|
||||
}
|
||||
|
||||
static int _seek_stream(void* datasource, ogg_int64_t offset, int whence) {
|
||||
hsStream* s = static_cast<hsStream*>(datasource);
|
||||
switch (whence) {
|
||||
case SEEK_CUR:
|
||||
s->skip(offset);
|
||||
break;
|
||||
case SEEK_SET:
|
||||
s->seek(offset);
|
||||
break;
|
||||
case SEEK_END:
|
||||
s->seek(s->size() - offset);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long _tell_stream(void* datasource) {
|
||||
hsStream* s = static_cast<hsStream*>(datasource);
|
||||
return s->pos();
|
||||
}
|
||||
|
||||
static ov_callbacks s_callbacks = {
|
||||
(size_t(*)(void *, size_t, size_t, void *))_read_stream,
|
||||
(int (*)(void *, ogg_int64_t, int))_seek_stream,
|
||||
(int (*)(void *))NULL,
|
||||
(long (*)(void *))_tell_stream,
|
||||
};
|
||||
|
||||
PyObject* inspect_vorbisfile(PyObject*, PyObject* args) {
|
||||
pyStream* stream;
|
||||
pyWAVHeader* header;
|
||||
if (!PyArg_ParseTuple(args, "OO", &stream, &header)) {
|
||||
PyErr_SetString(PyExc_TypeError, "inspect_vorbisfile expects an hsStream, plWAVHeader");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The OGG file may actually be in Blender's memory, so we will use hsStream. Therefore,
|
||||
// we must tell vorbisfile how to do this.
|
||||
OggVorbis_File vorbis;
|
||||
int result = ov_open_callbacks(stream->fThis, &vorbis, NULL, 0, s_callbacks);
|
||||
if (result < 0) {
|
||||
PyErr_Format(PyExc_RuntimeError, "vorbisfile ov_open_callbacks: %d", result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
header->fThis->setFormatTag(plWAVHeader::kPCMFormatTag);
|
||||
header->fThis->setBitsPerSample(BITS_PER_SAMPLE);
|
||||
vorbis_info* info = ov_info(&vorbis, -1);
|
||||
header->fThis->setNumChannels(info->channels);
|
||||
header->fThis->setNumSamplesPerSec(info->rate);
|
||||
unsigned short align = (BITS_PER_SAMPLE * info->channels) >> 3;
|
||||
header->fThis->setBlockAlign(align);
|
||||
header->fThis->setAvgBytesPerSec(info->rate * align);
|
||||
|
||||
// This behavior was copied and pasted from CWE
|
||||
ogg_int64_t size = (ov_pcm_total(&vorbis, -1) - 1) * align;
|
||||
|
||||
// Cleanup
|
||||
ov_clear(&vorbis);
|
||||
|
||||
// We got the plWAVHeader from Python because we don't link against PyHSPlasma, only libHSPlasma
|
||||
// Therefore, we only need to return the size.
|
||||
return PyLong_FromSsize_t(size);
|
||||
}
|
||||
|
||||
};
|
Reference in New Issue
Block a user