first FFmpeg / avcodoc commit (does NOT compile)

git-svn-id: https://openmw.svn.sourceforge.net/svnroot/openmw/trunk@24 ea6a568a-9f4f-0410-981a-c910a81bb256
actorid
nkorslund 16 years ago
parent 1974b68dcd
commit a99139cd2f

@ -39,6 +39,7 @@ Dependencies needed to build OpenMW:
OGRE 1.4.5 (3d engine)
OIS-1.0.0 (input system)
OpenAL (3d sound system)
libavcodec (MP3 library)
gcc and g++ (C++ compiler)
GNU make (build tool for C++ files)
DMD 1.031 (D compiler)
@ -46,11 +47,11 @@ DMD 1.031 (D compiler)
The above versions are the ones I have tested recently, but other
versions might work. OGRE and OIS will require their own set of
dependencies. I recommend using an automated package tool to install
as many of these as possible. On ubuntu, try typing:
versions might work. OGRE, OIS and the other libraries have
dependencies of their own, so I recommend using an automated package
tool to install as many of these as possible. On ubuntu, try typing:
sudo apt-get install libogre-dev libalut0 libois-dev build-essential g++ gdc
sudo apt-get install libogre-dev libavcodec-dev libois-dev build-essential g++ gdc
If you want to install Ogre, OpenAL or OIS manually, try:
OGRE: http://ogre3d.org/
@ -68,6 +69,9 @@ currently two choices for the D compiler, DMD and GDC. DMD is the
completely open source frontend to GCC (The GNU compiler.) Both should
work equally well with OpenMW.
If you want to install GDC manually, go to
http://sourceforge.net/projects/dgcc
If you want to use DMD instead, it can be found at:
http://digitalmars.com/d/1.0/dmd-linux.html

@ -11,13 +11,21 @@ NIFFLAGS=
# Compiler settings for Ogre + OIS. Change as needed.
OGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags OGRE OIS openal`
# Compiler settings for ffmpeg. Change as needed.
AVGCC=$(CXX) $(CXXFLAGS) `pkg-config --cflags libavcodec libavformat`
# Ogre C++ files, on the form ogre/cpp_X.cpp. Only the first file is
# passed to the compiler, the rest are dependencies.
ogre_cpp=ogre framelistener interface overlay bsaarchive
# FFmpeg files, in the form sound/cpp_X.cpp. Only the first file is
# passed to the compiler, the rest are dependencies.
avcodec_cpp=avcodec
## The rest of this file is automatic ##
ogre_cpp_files=$(ogre_cpp:%=ogre/cpp_%.cpp)
avcodec_cpp_files=$(avcodec_cpp:%=sound/cpp_%.cpp)
d_files=$(wildcard */*.d) $(wildcard monster/util/*.d)
d_files_nif=$(wildcard nif/*.d) $(wildcard util/*.d) $(wildcard core/memory.d) $(wildcard monster/util/*.d)
@ -30,13 +38,16 @@ d_objs_nif=$(d_files_nif:%.d=nifobjs/%.o)
.PHONY: cpp all clean makedirs
# By default, make will only build the Ogre C++ sources.
cpp: cpp_ogre.o
cpp: cpp_ogre.o cpp_avcodec.o
all: makedirs openmw esmtool niftool bsatool bored
cpp_ogre.o: $(ogre_cpp_files)
$(OGCC) -c $<
cpp_avcodec.o: $(avcodec_cpp_files)
$(AVGCC) -c $<
objs/%.o: %.d makedirs
$(DMD) -c $< -of$@
@ -62,11 +73,11 @@ makedirs:
mkdir -p nifobjs/monster/util
mkdir -p nifobjs/bsa
openmw: openmw.d cpp_ogre.o $(d_objs)
$(DMD) $^ -of$@ -L-lalut -L-lopenal -L-lOgreMain -L-lOIS
openmw: openmw.d cpp_ogre.o cpp_avcodec.o $(d_objs)
$(DMD) $^ -of$@ -L-lopenal -L-lOgreMain -L-lOIS -L-lavcodec -L-lavformat
esmtool: esmtool.d cpp_ogre.o $(d_objs)
$(DMD) $^ -of$@ -L-lalut -L-lopenal -L-lOgreMain -L-lOIS
esmtool: esmtool.d cpp_ogre.o cpp_avcodec.o $(d_objs)
$(DMD) $^ -of$@ -L-lopenal -L-lOgreMain -L-lOIS -L-lavcodec -L-lavformat
niftool: niftool.d $(d_objs_nif)
$(DMD) $^ -of$@
@ -78,6 +89,6 @@ bored: bored.d
$(DMD) $^
clean:
-rm -f cpp_ogre.o
-rm -f cpp_ogre.o cpp_avcodec.o bored.o bsafile.o bsatool.o esmtool.o niftool.o openmw.o
-rm -f openmw esmtool niftool bsatool bored
-rm -rf objs/ nifobjs/ dsss_objs/

@ -4,6 +4,6 @@
make || exit 1
gdc -Wall -g -fversion=Posix -o openmw openmw.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o -lalut -lopenal -lm -lOgreMain -lOIS -lstdc++
gdc -Wall -g -fversion=Posix -o openmw openmw.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o cpp_avcodec.o -lopenal -lm -lOgreMain -lOIS -lavcodec -lavformat -lstdc++
gdc -Wall -g -fversion=Posix -o esmtool esmtool.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o -lalut -lopenal -lm -lOgreMain -lOIS -lstdc++
gdc -Wall -g -fversion=Posix -o esmtool esmtool.d core/*.d ogre/*.d nif/*.d util/*.d bsa/*.d monster/util/*.d input/*.d sound/*.d scene/*.d esm/*.d cpp_ogre.o cpp_avcodec.o -lopenal -lm -lOgreMain -lOIS -lavcodec -lavformat -lstdc++

@ -4,7 +4,7 @@
[openmw.d]
# Add libraries and the two C++ object files
buildflags = -llOgreMain -llalut -llopenal -llOIS cpp_ogre.o
buildflags = -llOgreMain -llopenal -llOIS -llavcodec -llavformat cpp_ogre.o cpp_avcodec.o
# Make sure the C++ object files are built first
version(Windows) {
@ -34,7 +34,7 @@ prebuild += dsss clean niftool
[esmtool.d]
# Because of interdepencies between the ESM code and the resource
# manager, we have to include all the C++ stuff.
buildflags = -llOgreMain -llalut -llopenal -llOIS cpp_ogre.o
buildflags = -llOgreMain -llopenal -llOIS -llavcodec -llavformat cpp_ogre.o cpp_avcodec.o

@ -32,13 +32,6 @@ import sound.alc;
import std.stdio;
import std.string;
ALCdevice *Device = null;
ALCcontext *Context = null;
// Temporarilly use ALUT for data loading until something better is picked
extern (C) ALboolean alutInitWithoutContext(int *argc, char **argv);
extern (C) ALboolean alutExit();
class SoundException : Exception
{
this(char[] caller, char[] msg) { super(caller ~ " SoundException: " ~ msg); }
@ -47,6 +40,9 @@ class SoundException : Exception
MusicManager jukebox;
MusicManager battleMusic;
ALCdevice *Device = null;
ALCcontext *Context = null;
void initializeSound()
{
Device = alcOpenDevice(null);
@ -57,7 +53,6 @@ void initializeSound()
"Failed to initialize music device");
alcMakeContextCurrent(Context);
alutInitWithoutContext(null, null);
// Gross HACK: We should use the default model (inverse distance clamped).
// But without a proper rolloff factor, distance attenuation is completely
@ -73,8 +68,6 @@ void shutdownSound()
jukebox.disableMusic();
battleMusic.disableMusic();
alutExit();
alcMakeContextCurrent(null);
if(Context) alcDestroyContext(Context);
Context = null;

@ -0,0 +1,40 @@
extern (C):
// A unique handle that represents an AV file
typedef void* AVFile;
// A unique handle representing an audio stream
typedef void* AVAudio;
// In case we ever decide to implement more codec backends, here's what
// these functions need to do...
// Open the named file, and return a unique handle representing it.
// Returns NULL on error
AVFile cpp_openAVFile(char *fname);
// Close the file handle, invalidating all streams taken from it
void cpp_closeAVFile(AVFile file);
// Get a unique handle to an audio stream in the file. The given number
// is for files that can contain multiple audio streams (generally you
// would pass 0, for the first audio stream)
void *cpp_getAVAudioStream(AVFile file, int streamnum);
// Get audio info representing the current stream. Returns 0 for success
// (not likely to fail)
int cpp_getAVAudioInfo(AVAudio stream, int *rate, int *channels, int *bits);
// Decode the next bit of data for the given audio stream. The function
// must provide no less than the requested number of bytes, except for
// end-of-stream conditions, and is responsible for buffering data. For
// files with multiple streams, it must take care to preserve data for
// any stream that has had a stream handle returned.
// eg. if a file has one video stream and 2 audio streams and the app
// gets a handle to the video stream and one audio stream, it must
// not destroy video data for subsequent calls to cpp_getAVVideoData if
// it has to read over it while decoding the audio stream. The other
// audio stream's data, however, may be discarded.
// Returns the number of bytes written to the buffer, which will be no
// more than the provided length.
int cpp_getAVAudioData(AVAudio stream, void *data, int length);

@ -0,0 +1,209 @@
/*
OpenMW - The completely unofficial reimplementation of Morrowind
Copyright (C) 2008 Nicolay Korslund
Email: < korslund@gmail.com >
WWW: http://openmw.snaptoad.com/
This file (cpp_avcodec.cpp) is part of the OpenMW package.
OpenMW is distributed as free software: you can redistribute it
and/or modify it under the terms of the GNU General Public License
version 3, as published by the Free Software Foundation.
This program 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
version 3 along with this program. If not, see
http://www.gnu.org/licenses/ .
*/
#include <stdio.h>
extern "C" { // the headers don't do this..
#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>
}
#include <vector>
using std::vector;
struct MyFile {
AVFormatContext *FmtCtx;
struct MyStream {
MyFile *parent;
AVCodecContext *CodecCtx;
int StreamNum;
vector<uint8_t> Data;
vector<char> DecodedData;
};
vector<MyStream> Streams;
};
// TODO:
// extern "C" MyFile::MyStream *cpp_getAVVideoStream(MyFile *file, int streamnum);
// extern "C" int cpp_getAVVideoInfo(MyFile::MyStream *stream, float *fps, int *width, int * height);
// extern "C" int cpp_getAVVideoData(MyFile::MyStream *stream, char *data, int length);
extern "C" MyFile *cpp_openAVFile(char *fname)
{
static bool done = false;
if(!done) { av_register_all();
av_log_set_level(AV_LOG_ERROR);}
done = true;
MyFile *file = new MyFile;
if(av_open_input_file(&file->FmtCtx, fname, NULL, 0, NULL) == 0)
{
if(av_find_stream_info(file->FmtCtx) >= 0)
return file;
av_close_input_file(file->FmtCtx);
}
delete file;
return NULL;
}
extern "C" void cpp_closeAVFile(MyFile *file)
{
if(!file) return;
for(size_t i = 0;i < file->Streams.size();i++)
{
avcodec_close(file->Streams[i].CodecCtx);
file->Streams[i].Data.clear();
file->Streams[i].DecodedData.clear();
}
file->Streams.clear();
av_close_input_file(file->FmtCtx);
delete file;
}
extern "C" MyFile::MyStream *cpp_getAVAudioStream(MyFile *file, int streamnum)
{
if(!file) return NULL;
for(unsigned int i = 0;i < file->FmtCtx->nb_streams;i++)
{
if(file->FmtCtx->streams[i]->codec->codec_type != CODEC_TYPE_AUDIO)
continue;
if(streamnum == 0)
{
MyFile::MyStream stream;
stream.parent = file;
stream.CodecCtx = file->FmtCtx->streams[i]->codec;
stream.StreamNum = i;
AVCodec *codec = avcodec_find_decoder(stream.CodecCtx->codec_id);
if(!codec) return NULL;
if(avcodec_open(stream.CodecCtx, codec) < 0)
return NULL;
file->Streams.push_back(stream);
return &file->Streams[file->Streams.size()-1];
}
streamnum--;
}
return NULL;
}
extern "C" int cpp_getAVAudioInfo(MyFile::MyStream *stream,
int *rate, int *channels, int *bits)
{
if(!stream) return 1;
if(rate) *rate = stream->CodecCtx->sample_rate;
if(channels) *channels = stream->CodecCtx->channels;
if(bits) *bits = 16;
return 0;
}
static int getNextPacket(MyFile *file)
{
AVPacket packet;
while(av_read_frame(file->FmtCtx, &packet) >= 0)
{
for(vector<MyFile::MyStream>::iterator i = file->Streams.begin();
i != file->Streams.end();i++)
{
if(i->StreamNum == packet.stream_index)
{
size_t idx = i->Data.size();
i->Data.resize(idx + packet.size);
memcpy(&i->Data[idx], packet.data, packet.size);
av_free_packet(&packet);
return 0;
}
}
av_free_packet(&packet);
}
return 1;
}
extern "C" int cpp_getAVAudioData(MyFile::MyStream *stream, char *data, int length)
{
if(!stream) return 0;
int dec = 0;
while(dec < length)
{
if(stream->DecodedData.size() == 0)
{
while(stream->Data.size() == 0)
{
if(getNextPacket(stream->parent) != 0)
break;
}
int insize = stream->Data.size();
if(insize == 0)
break;
// Temporarilly add padding to the input data since some
// codecs read in larger chunks and may accidently read
// past the end of the allocated buffer
stream->Data.resize(insize + FF_INPUT_BUFFER_PADDING_SIZE);
stream->DecodedData.resize(AVCODEC_MAX_AUDIO_FRAME_SIZE);
int16_t *ptr = (int16_t*)&stream->DecodedData[0];
int size = stream->DecodedData.size();
int len = avcodec_decode_audio2(stream->CodecCtx, ptr, &size,
&stream->Data[0], insize);
if(len < 0)
{
stream->Data.resize(insize);
break;
}
int datarem = insize-len;
if(datarem)
memmove(&stream->Data[0], &stream->Data[len], datarem);
stream->Data.resize(datarem);
stream->DecodedData.resize(size);
if(stream->DecodedData.size() == 0)
break;
}
size_t rem = length-dec;
if(rem > stream->DecodedData.size())
rem = stream->DecodedData.size();
memcpy(data, &stream->DecodedData[0], rem);
data += rem;
dec += rem;
if(rem < stream->DecodedData.size())
memmove(&stream->DecodedData[0], &stream->DecodedData[rem],
stream->DecodedData.size() - rem);
stream->DecodedData.resize(stream->DecodedData.size()-rem);
}
return dec;
}

@ -23,6 +23,7 @@
module sound.music;
import sound.avcodec;
import sound.audio;
import sound.al;
@ -32,10 +33,6 @@ import std.string;
import core.config;
import core.resource;
extern (C) ALuint alutCreateBufferFromFile(char *filename);
extern (C) ALenum alutGetError();
extern (C) ALchar *alutGetErrorString(ALenum err);
// Simple music player, has a playlist and can pause/resume music.
struct MusicManager
{
@ -45,6 +42,9 @@ struct MusicManager
const float fadeInRate = 0.10;
const float fadeOutRate = 0.35;
// Maximum buffer length, divided up among OpenAL buffers
const uint bufLength = 128*1024;
// Volume
ALfloat volume, maxVolume;
@ -61,9 +61,14 @@ struct MusicManager
bool musicOn;
ALuint sID;
ALuint bIDs[1];
ALuint bIDs[4];
ubyte[] readData;
ALenum bufFormat;
ALint bufRate;
AVFile fileHandle;
AVAudio audioHandle;
ubyte[] outData;
// Which direction are we currently fading, if any
enum Fade { None = 0, In, Out }
@ -77,6 +82,8 @@ struct MusicManager
this.name = name;
sID = 0;
foreach(ref b; bIDs) b = 0;
outData.length = bufLength / bIDs.length;
fileHandle = null;
musicOn = false;
updateVolume();
}
@ -156,6 +163,10 @@ struct MusicManager
foreach(ref b; bIDs) b = 0;
checkALError();
if(fileHandle) cpp_closeAVFile(fileHandle);
fileHandle = null;
audioHandle = null;
// End of list? Randomize and start over
if(index == playlist.length)
{
@ -163,37 +174,97 @@ struct MusicManager
index = 0;
}
readData.length = 128*1024 / bIDs.length;
// FIXME: Should load up and queue 3 or 4 buffers here instead of trying to
// load it all into one (when we switch away from ALUT).
char *fname = toStringz(playlist[index]);
bIDs[0] = alutCreateBufferFromFile(fname);
if(!bIDs[0])
alGenBuffers(bIDs.length, bIDs.ptr);
if(checkALError() != AL_NO_ERROR)
{
writefln("Unable to load music track %s: %s", playlist[index],
toString(alutGetErrorString(alutGetError())));
writefln("Unable to create %d buffers", bIDs.length);
alDeleteSources(1, &sID);
checkALError();
sID = 0;
index++;
return;
}
alSourcei(sID, AL_BUFFER, bIDs[0]);
fileHandle = cpp_openAVFile(toStringz(playlist[index]));
if(!fileHandle)
{
writefln("Unable to open %s", playlist[index]);
goto errclose;
}
audioHandle = cpp_getAVAudioStream(fileHandle, 0);
if(!audioHandle)
{
writefln("Unable to load music track %s", playlist[index]);
goto errclose;
}
int ch, bits, rate;
if(cpp_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
{
writefln("Unable to get info for music track %s", playlist[index]);
goto errclose;
}
bufRate = rate;
bufFormat = 0;
if(bits == 8)
{
if(ch == 1) bufFormat = AL_FORMAT_MONO8;
if(ch == 2) bufFormat = AL_FORMAT_STEREO8;
if(ch == 4) bufFormat = alGetEnumValue("AL_FORMAT_QUAD8");
}
if(bits == 16)
{
if(ch == 1) bufFormat = AL_FORMAT_MONO16;
if(ch == 2) bufFormat = AL_FORMAT_STEREO16;
if(ch == 4) bufFormat = alGetEnumValue("AL_FORMAT_QUAD16");
}
if(bufFormat == 0)
{
writefln("Unhandled format (%d channels, %d bits) for music track %s", ch, bits, playlist[index]);
goto errclose;
}
foreach(int i, ref b; bIDs)
{
int length = cpp_getAVAudioData(audioHandle, outData.ptr, outData.length);
if(length) alBufferData(b, bufFormat, outData.ptr, length, bufRate);
if(length == 0 || checkALError() != AL_NO_ERROR)
{
if(i == 0)
{
writefln("No audio data in music track %s", playlist[index]);
goto errclose;
}
alDeleteBuffers(bIDs.length-i, bIDs.ptr+i);
checkALError();
bIDs[i..$] = 0;
break;
}
}
alSourceQueueBuffers(sID, bIDs.length, bIDs.ptr);
alSourcePlay(sID);
if(checkALError() != AL_NO_ERROR)
{
writefln("Unable to start music track %s", playlist[index]);
alSourceStop(sID);
alDeleteSources(1, &sID);
alDeleteBuffers(bIDs.length, bIDs.ptr);
checkALError();
sID = 0;
foreach(ref b; bIDs) b = 0;
goto errclose;
}
index++;
return;
errclose:
if(fileHandle) cpp_closeAVFile(fileHandle);
fileHandle = null;
audioHandle = null;
alSourceStop(sID);
alDeleteSources(1, &sID);
alDeleteBuffers(bIDs.length, bIDs.ptr);
checkALError();
sID = 0;
foreach(ref b; bIDs) b = 0;
index++;
}
// Start playing the jukebox
@ -210,15 +281,22 @@ struct MusicManager
// Disable music
void disableMusic()
{
if(fileHandle) cpp_closeAVFile(fileHandle);
fileHandle = null;
audioHandle = null;
if(sID)
{
alSourceStop(sID);
alDeleteSources(1, &sID);
alDeleteBuffers(bIDs.length, bIDs.ptr);
checkALError();
sID = 0;
foreach(ref b; bIDs) b = 0;
}
alDeleteBuffers(bIDs.length, bIDs.ptr);
checkALError();
foreach(ref b; bIDs) b = 0;
musicOn = false;
}
@ -245,14 +323,14 @@ struct MusicManager
private bool isPlaying()
{
if(!sID) return false;
/* Use this when we can do streaming..
ALint count;
alGetSourcei(sID, AL_BUFFERS_PROCESSED, &count);
if(checkALError() != AL_NO_ERROR) return false;
for(int i = 0;i < count;i++)
{
int length = GetData(readData.ptr, readData.length);
int length = cpp_getAVAudioData(audioHandle, outData.ptr, outData.length);
if(length <= 0)
{
if(i == 0)
@ -269,7 +347,7 @@ struct MusicManager
alSourceUnqueueBuffers(sID, 1, &bid);
if(checkALError() == AL_NO_ERROR)
{
alBufferData(bid, dataFreq, dataFormat, length, readData.ptr);
alBufferData(bid, bufFormat, outData.ptr, length, bufRate);
alSourceQueueBuffers(sID, 1, &bid);
checkALError();
}
@ -279,13 +357,6 @@ struct MusicManager
alGetSourcei(sID, AL_SOURCE_STATE, &state);
if(state != AL_PLAYING) alSourcePlay(sID);
return (checkALError() == AL_NO_ERROR);
*/
ALint state;
alGetSourcei(sID, AL_SOURCE_STATE, &state);
if(checkALError() != AL_NO_ERROR || state == AL_STOPPED) return false;
if(state != AL_PLAYING) alSourcePlay(sID);
return (checkALError() == AL_NO_ERROR);
}
// Check if the music has died. This function is also used for fading.

@ -23,6 +23,7 @@
module sound.sfx;
import sound.avcodec;
import sound.audio;
import sound.al;
@ -30,8 +31,7 @@ import core.config;
import core.resource;
import std.string;
extern (C) ALuint alutCreateBufferFromFile(char *filename);
import std.stdio;
// Handle for a sound resource. This struct represents one sound
// effect file (not a music file, those are handled differently
@ -57,11 +57,81 @@ struct SoundFile
{
name = file;
loaded = true;
loaded = false;
refs = 0;
bID = 0;
ubyte[] outData;
AVFile fileHandle = cpp_openAVFile(toStringz(file));
AVAudio audioHandle = cpp_getAVAudioStream(fileHandle, 0);
if(!fileHandle)
{
writefln("Unable to open %s", file);
goto errclose;
}
if(!audioHandle)
{
writefln("Unable to load sound %s", file);
goto errclose;
}
int ch, bits, rate;
if(cpp_getAVAudioInfo(audioHandle, &rate, &ch, &bits) != 0)
{
writefln("Unable to get info for sound %s", file);
goto errclose;
}
int fmt = 0;
if(bits == 8)
{
if(ch == 1) fmt = AL_FORMAT_MONO8;
if(ch == 2) fmt = AL_FORMAT_STEREO8;
if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD8");
}
if(bits == 16)
{
if(ch == 1) fmt = AL_FORMAT_MONO16;
if(ch == 2) fmt = AL_FORMAT_STEREO16;
if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD16");
}
if(fmt == 0)
{
writefln("Unhandled format (%d channels, %d bits) for sound %s", ch, bits, file);
goto errclose;
}
int total = 0;
do
{
// Grow by an arbitrary amount. Should be big enough to get the
// whole sound in one or two iterations, but not allocate too much
// memory in case its short
outData.length = outData.length+8192;
int length = cpp_getAVAudioData(audioHandle, outData.ptr+total, outData.length-total);
total += length;
}
while(total == outData.length);
if(total)
{
alGenBuffers(1, &bID);
alBufferData(bID, fmt, outData.ptr, total, rate);
if(checkALError() != AL_NO_ERROR)
{
writefln("Unable to load sound %s", file);
alDeleteBuffers(1, &bID);
bID = 0;
}
else loaded = true;
}
bID = alutCreateBufferFromFile(toStringz(file));
if(!bID) fail("Failed to open sound file " ~ file);
errclose:
if(fileHandle) cpp_closeAVFile(fileHandle);
fileHandle = null;
audioHandle = null;
}
// Get an instance of this resource.

Loading…
Cancel
Save