Files
BlitzNext/Runtime/gfx/gxaudio.cpp
T
Michael Fabian 'Xaymar' Dirks a16218e1d5 runtime: CMake-ify gx
2019-01-18 17:03:37 +01:00

324 lines
6.8 KiB
C++

#include "gxaudio.hpp"
#include <fmod.h>
#include "std.hpp"
struct StaticChannel : public gxChannel {
virtual void play() = 0;
};
struct SoundChannel : public gxChannel {
SoundChannel() : channel(-1) {}
void set(int n)
{
channel = n;
}
void stop()
{
FSOUND_StopSound(channel);
}
void setPaused(bool paused)
{
FSOUND_SetPaused(channel, paused);
}
void setPitch(int pitch)
{
FSOUND_SetFrequency(channel, pitch);
}
void setVolume(float volume)
{
FSOUND_SetVolume(channel, volume * 255.0f);
}
void setPan(float pan)
{
FSOUND_SetPan(channel, (pan + 1) * 127.5f);
}
void set3d(const float pos[3], const float vel[3])
{
FSOUND_3D_SetAttributes(channel, (float*)pos, (float*)vel);
}
bool isPlaying()
{
return FSOUND_IsPlaying(channel) ? true : false;
}
private:
int channel;
};
struct CDChannel : public gxChannel {
void play(int track, int mode)
{
stop();
int cd_mode = FSOUND_CD_PLAYONCE;
if (mode == gxAudio::CD_MODE_LOOP)
cd_mode = FSOUND_CD_PLAYLOOPED;
else if (mode == gxAudio::CD_MODE_ALL)
cd_mode = FSOUND_CD_PLAYCONTINUOUS;
FSOUND_CD_SetPlayMode(0, cd_mode);
FSOUND_CD_Play(0, track);
}
void stop()
{
FSOUND_CD_Stop(0);
}
void setPaused(bool paused)
{
FSOUND_CD_SetPaused(0, paused);
}
void setPitch(int pitch) {}
void setVolume(float volume)
{
FSOUND_CD_SetVolume(0, volume * 255.0f);
}
void setPan(float pan) {}
void set3d(const float pos[3], const float vel[3]) {}
bool isPlaying()
{
return true;
}
};
struct StreamChannel : public StaticChannel {
StreamChannel(FSOUND_STREAM* s) : stream(s)
{
channel = FSOUND_Stream_Play(FSOUND_FREE, stream);
}
~StreamChannel()
{
FSOUND_Stream_Close(stream);
}
void play()
{
stop();
channel = FSOUND_Stream_Play(FSOUND_FREE, stream);
}
void stop()
{
FSOUND_Stream_Stop(stream);
channel = -1;
}
void setPaused(bool paused)
{
FSOUND_SetPaused(channel, paused);
}
void setPitch(int pitch)
{
FSOUND_SetFrequency(channel, pitch);
}
void setVolume(float volume)
{
FSOUND_SetVolume(channel, volume * 255.0f);
}
void setPan(float pan)
{
FSOUND_SetPan(channel, (pan + 1) * 127.5f);
}
void set3d(const float pos[3], const float vel[3]) {}
bool isPlaying()
{
return FSOUND_IsPlaying(channel) ? true : false;
}
private:
FSOUND_STREAM* stream;
int channel;
};
struct MusicChannel : public StaticChannel {
MusicChannel(FMUSIC_MODULE* m) : module(m)
{
play();
}
~MusicChannel()
{
FMUSIC_FreeSong(module);
}
void play()
{
FMUSIC_PlaySong(module);
}
void stop()
{
FMUSIC_StopSong(module);
}
void setPaused(bool paused)
{
FMUSIC_SetPaused(module, paused);
}
void setPitch(int pitch) {}
void setVolume(float volume)
{
FMUSIC_SetMasterVolume(module, volume * 255.0f);
}
void setPan(float pan) {}
void set3d(const float pos[3], const float vel[3]) {}
bool isPlaying()
{
return FMUSIC_IsFinished(module) ? false : true;
}
private:
FMUSIC_MODULE* module;
};
static set<gxSound*> sound_set;
static vector<gxChannel*> channels;
static map<string, StaticChannel*> songs;
static CDChannel* cdChannel;
static int next_chan;
static vector<SoundChannel*> soundChannels;
static gxChannel* allocSoundChannel(int n)
{
SoundChannel* chan = 0;
for (int k = 0; k < soundChannels.size(); ++k) {
chan = soundChannels[next_chan];
if (!chan) {
chan = soundChannels[next_chan] = new SoundChannel();
channels.push_back(chan);
} else if (chan->isPlaying()) {
chan = 0;
}
if (++next_chan == soundChannels.size())
next_chan = 0;
if (chan)
break;
}
if (!chan) {
next_chan = soundChannels.size();
soundChannels.resize(soundChannels.size() * 2);
for (int k = next_chan; k < soundChannels.size(); ++k)
soundChannels[k] = 0;
chan = soundChannels[next_chan++] = new SoundChannel();
channels.push_back(chan);
}
chan->set(n);
return chan;
}
gxAudio::gxAudio(gxRuntime* r) : runtime(r)
{
next_chan = 0;
soundChannels.resize(4096);
for (int k = 0; k < 4096; ++k)
soundChannels[k] = 0;
cdChannel = new CDChannel();
channels.push_back(cdChannel);
}
gxAudio::~gxAudio()
{
//free all channels
for (; channels.size(); channels.pop_back())
delete channels.back();
//free all sound_set
while (sound_set.size())
freeSound(*sound_set.begin());
soundChannels.clear();
songs.clear();
FSOUND_Close();
}
gxChannel* gxAudio::play(FSOUND_SAMPLE* sample)
{
int n = FSOUND_PlaySound(FSOUND_FREE, sample);
return n >= 0 ? allocSoundChannel(n) : 0;
}
gxChannel* gxAudio::play3d(FSOUND_SAMPLE* sample, const float pos[3], const float vel[3])
{
int n = FSOUND_PlaySoundEx(FSOUND_FREE, sample, 0, true);
if (n < 0)
return 0;
FSOUND_3D_SetAttributes(n, (float*)pos, (float*)vel);
FSOUND_SetPaused(n, false);
return allocSoundChannel(n);
}
void gxAudio::pause() {}
void gxAudio::resume() {}
gxSound* gxAudio::loadSound(const string& f, bool use3d)
{
int flags = FSOUND_NORMAL | (use3d ? FSOUND_FORCEMONO : FSOUND_2D);
FSOUND_SAMPLE* sample = FSOUND_Sample_Load(FSOUND_FREE, f.c_str(), flags, 0, 0);
if (!sample)
return 0;
gxSound* sound = new gxSound(this, sample);
sound_set.insert(sound);
return sound;
}
gxSound* gxAudio::verifySound(gxSound* s)
{
return sound_set.count(s) ? s : 0;
}
void gxAudio::freeSound(gxSound* s)
{
if (sound_set.erase(s))
delete s;
}
void gxAudio::setPaused(bool paused)
{
FSOUND_SetPaused(FSOUND_ALL, paused);
}
void gxAudio::setVolume(float volume) {}
void gxAudio::set3dOptions(float roll, float dopp, float dist)
{
FSOUND_3D_SetRolloffFactor(roll);
FSOUND_3D_SetDopplerFactor(dopp);
FSOUND_3D_SetDistanceFactor(dist);
}
void gxAudio::set3dListener(const float pos[3], const float vel[3], const float forward[3], const float up[3])
{
FSOUND_3D_Listener_SetAttributes((float*)pos, (float*)vel, forward[0], forward[1], forward[2], up[0], up[1], up[2]);
FSOUND_Update();
}
gxChannel* gxAudio::playFile(const string& t, bool use_3d)
{
string f = tolower(t);
StaticChannel* chan = 0;
map<string, StaticChannel*>::iterator it = songs.find(f);
if (it != songs.end()) {
chan = it->second;
chan->play();
return chan;
} else if (f.find(".raw") != string::npos || f.find(".wav") != string::npos || f.find(".mp2") != string::npos
|| f.find(".mp3") != string::npos || f.find(".ogg") != string::npos || f.find(".wma") != string::npos
|| f.find(".asf") != string::npos) {
FSOUND_STREAM* stream = FSOUND_Stream_Open(f.c_str(), use_3d, 0, 0);
if (!stream)
return 0;
chan = new StreamChannel(stream);
} else {
FMUSIC_MODULE* module = FMUSIC_LoadSong(f.c_str());
if (!module)
return 0;
chan = new MusicChannel(module);
}
channels.push_back(chan);
songs[f] = chan;
return chan;
}
gxChannel* gxAudio::playCDTrack(int track, int mode)
{
cdChannel->play(track, mode);
return cdChannel;
}