#include "std.h"
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "emul.h"
#include "vars.h"
#include "bass.h"
#include "snd_bass.h"
#include "gshle.h"
#include "gs.h"
#include "init.h"
#include "util.h"
#ifdef MOD_GSBASS
void GSHLE::reportError(const char *err, bool fatal)
{
color(CONSCLR_ERROR);
printf("BASS library reports error in %s\n", err);
color(CONSCLR_ERRCODE);
printf("error code is 0x%04X\n", BASS::ErrorGetCode());
if(fatal)
{
exit();
}
}
void GSHLE::runBASS()
{
if(BASS::Initialized)
return;
if (BASS::Init(-1, conf.sound.fq, BASS_DEVICE_LATENCY, wnd, nullptr))
{
DWORD len = BASS::GetConfig(BASS_CONFIG_UPDATEPERIOD);
BASS_INFO info;
BASS::GetInfo(&info);
BASS::SetConfig(BASS_CONFIG_BUFFER, len + info.minbuf);
color(CONSCLR_HARDITEM);
printf("BASS device latency is ");
color(CONSCLR_HARDINFO);
printf("%lums\n", len + info.minbuf);
}
else
{
color(CONSCLR_WARNING);
reportError("warning: can't use default BASS device, trying silence\n", false);
if (!BASS::Init(-2, 11025, 0, wnd, nullptr))
errexit("can't init BASS");
}
BASS::Initialized = true;
hmod = 0;
for (int ch = 0; ch < 4; ch++)
chan[ch].bass_ch = 0;
DebugCh.bass_ch = 0;
}
void GSHLE::reset_sound()
{
// runBASS();
// BASS_Stop(); // todo: move to silent state?
}
DWORD CALLBACK gs_render(HSTREAM handle, void *buffer, DWORD length, void *user);
void GSHLE::initChannels()
{
if (chan[0].bass_ch)
return;
for (int ch = 0; ch < 4; ch++)
{
chan[ch].bass_ch = BASS::StreamCreate(conf.sound.fq, 1, BASS_SAMPLE_8BITS, gs_render, &chan[ch]);
if (!chan[ch].bass_ch)
reportError("BASS_StreamCreate()");
}
DebugCh.bass_ch = BASS::StreamCreate(conf.sound.fq, 1, BASS_SAMPLE_8BITS, gs_render, &DebugCh);
if(!DebugCh.bass_ch)
reportError("BASS_StreamCreate()");
}
void GSHLE::setmodvol(unsigned vol)
{
if (!hmod)
return;
runBASS();
float v = (int(vol) * conf.sound.bass_vol) / float(8192 * 64);
assert(v <= 1.0f);
if (!BASS::ChannelSetAttribute(hmod, BASS_ATTRIB_VOL, v))
reportError("BASS_ChannelSetAttribute() [music volume]");
}
void GSHLE::SetModSpeed()
{
// ╘єэъЎш эх юЄырцхэр, эхшчтхёЄэю т ъръшї яЁюуЁрььрї фрээр ъюьрэфр шёяюы№чєхЄё
if(!hmod)
return;
runBASS();
// printf("%s, speed=%u\n", __FUNCTION__, speed);
if(!BASS::ChannelSetAttribute(hmod, BASS_ATTRIB_MUSIC_SPEED, speed))
reportError("BASS_ChannelSetAttribute() [music speed]");
}
void GSHLE::init_mod()
{
runBASS();
if (hmod)
BASS::MusicFree(hmod);
hmod = 0;
hmod = BASS::MusicLoad(1, mod, 0, modsize, BASS_MUSIC_LOOP | BASS_MUSIC_POSRESET | BASS_MUSIC_RAMP, 0);
if (!hmod)
reportError("BASS_MusicLoad()", false);
setmodvol(modvol); // ╙ёЄрэютър эрўры№эющ уЁюьъюёЄш
}
void GSHLE::restart_mod(unsigned order, unsigned row)
{
if (!hmod)
return;
SetModSpeed();
if (!BASS::ChannelSetPosition(hmod, QWORD(MAKELONG(order,row)), BASS_POS_MUSIC_ORDER))
reportError("BASS_ChannelSetPosition() [music]");
if (!BASS::ChannelFlags(hmod, BASS_MUSIC_LOOP | BASS_MUSIC_POSRESET | BASS_MUSIC_RAMP, -1U))
reportError("BASS_ChannelFlags() [music]");
BASS::Start();
if (!BASS::ChannelPlay(hmod, FALSE/*TRUE*/))
reportError("BASS_ChannelPlay() [music]"); //molodcov_alex 0.36.2
mod_playing = 1;
}
void GSHLE::resetmod()
{
if (hmod)
BASS::MusicFree(hmod);
hmod = 0;
}
void GSHLE::resetfx()
{
runBASS();
for (int i = 0; i < 4; i++)
{
if (chan[i].bass_ch)
{
BASS::StreamFree(chan[i].bass_ch);
chan[i].bass_ch = 0;
}
}
}
DWORD GSHLE::modgetpos()
{
runBASS();
return (DWORD)BASS::ChannelGetPosition(hmod, BASS_POS_MUSIC_ORDER);
// return BASS_MusicGetOrderPosition(hmod);
}
void GSHLE::stop_mod()
{
runBASS();
if (!hmod)
return;
if(BASS::ChannelIsActive(hmod) != BASS_ACTIVE_PLAYING)
return;
if (!BASS::ChannelPause(hmod))
reportError("BASS_ChannelPause() [music]");
}
void GSHLE::cont_mod()
{
runBASS();
if (!hmod)
return;
if (!BASS::ChannelPlay(hmod, TRUE))
reportError("BASS_ChannelPlay() [music]");
}
void GSHLE::startfx(CHANNEL *ch, float pan)
{
initChannels();
float vol = (int(ch->volume) * conf.sound.gs_vol) / float(8192*64);
assert(vol <= 1.0f);
if(BASS::ChannelIsActive(ch->bass_ch) == BASS_ACTIVE_PLAYING)
{
if(!BASS::ChannelStop(ch->bass_ch))
reportError("BASS_ChannelStop()");
}
if (!BASS::ChannelSetAttribute(ch->bass_ch, BASS_ATTRIB_VOL, vol))
reportError("BASS_ChannelSetAttribute() [vol]");
if (!BASS::ChannelSetAttribute(ch->bass_ch, BASS_ATTRIB_FREQ, ch->freq))
reportError("BASS_ChannelSetAttribute() [freq]");
if (!BASS::ChannelSetAttribute(ch->bass_ch, BASS_ATTRIB_PAN, pan))
reportError("BASS_ChannelSetAttribute() [pan]");
{
DWORD len = BASS::GetConfig(BASS_CONFIG_UPDATEPERIOD);
BASS_INFO info;
BASS::GetInfo(&info);
BASS::SetConfig(BASS_CONFIG_BUFFER, len + info.minbuf);
}
if (!BASS::ChannelPlay(ch->bass_ch, FALSE))
reportError("BASS_ChannelPlay()");
}
void GSHLE::flush_gs_frame()
{
unsigned lvl;
if (!hmod || (lvl = BASS::ChannelGetLevel(hmod)) == -1U) lvl = 0;
gsleds[0].level = LOWORD(lvl) >> (15-4);
gsleds[0].attrib = 0x0D;
gsleds[1].level = HIWORD(lvl) >> (15-4);
gsleds[1].attrib = 0x0D;
for (int ch = 0; ch < 4; ch++)
{
if (chan[ch].bass_ch && (lvl = BASS::ChannelGetLevel(chan[ch].bass_ch)) != -1U)
{
lvl = max(HIWORD(lvl), LOWORD(lvl));
lvl >>= (15-4);
}
else
lvl = 0;
gsleds[ch+2].level = lvl;
gsleds[ch+2].attrib = 0x0F;
}
}
void GSHLE::debug_note(unsigned i)
{
if(BASS::ChannelIsActive(DebugCh.bass_ch) == BASS_ACTIVE_PLAYING)
{
if(!BASS::ChannelStop(DebugCh.bass_ch))
{
reportError("BASS_ChannelStop()");
}
}
DebugCh.volume = sample[i].volume;
DebugCh.ptr = 0;
DebugCh.start = sample[i].start;
DebugCh.loop = sample[i].loop;
DebugCh.end = sample[i].end;
unsigned note = sample[i].note;
DebugCh.freq = note2rate[note];
startfx(&DebugCh, 0);
}
void GSHLE::debug_save_note(unsigned i, const char *FileName)
{
int f = open(FileName, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);
if(f >= 0)
{
write(f, sample[i].start, sample[i].end);
close(f);
}
}
void GSHLE::debug_save_mod(const char *FileName)
{
int f = open(FileName, O_CREAT | O_TRUNC | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);
if(f >= 0)
{
write(f, mod, modsize);
close(f);
}
}
#endif