3 Commits
v1.6 ... v1.8

Author SHA1 Message Date
Jack Andersen
52cba61f76 Refactored audio supply dispatch across two passes 2016-07-04 15:08:00 -10:00
Jack Andersen
fe78a675d7 Change default volume to 80% to fill newfound headroom 2016-07-03 17:35:37 -10:00
Jack Andersen
3427515960 Add Starfox Adventures midi.wad support 2016-07-03 12:41:31 -10:00
8 changed files with 221 additions and 86 deletions

View File

@@ -132,7 +132,7 @@ struct AppCallback : boo::IApplicationCallback
int8_t m_lastChanProg = -1;
/* Control state */
float m_volume = 0.5f;
float m_volume = 0.8f;
float m_modulation = 0.f;
float m_pitchBend = 0.f;
bool m_updateDisp = false;
@@ -724,8 +724,27 @@ struct AppCallback : boo::IApplicationCallback
int idx = 0;
for (const auto& pair : songs)
{
const amuse::ContainerRegistry::SongData& sngData = pair.second;
int16_t grpId = sngData.m_groupId;
int16_t setupId = sngData.m_setupId;
if (sngData.m_groupId == -1 && sngData.m_setupId != -1)
{
for (const auto& pair : allSongGroups)
{
for (const auto& setup : pair.second.second->m_midiSetups)
{
if (setup.first == sngData.m_setupId)
{
grpId = pair.first;
break;
}
}
if (grpId != -1)
break;
}
}
amuse::Printf(_S(" %d %s (Group %d, Setup %d)\n"), idx++,
pair.first.c_str(), pair.second.m_groupId, pair.second.m_setupId);
pair.first.c_str(), grpId, setupId);
}
int userSel = 0;
@@ -757,7 +776,25 @@ struct AppCallback : boo::IApplicationCallback
}
}
/* Get group selection from user */
/* Get group selection via setup search */
if (m_groupId == -1 && m_setupId != -1)
{
for (const auto& pair : allSongGroups)
{
for (const auto& setup : pair.second.second->m_midiSetups)
{
if (setup.first == m_setupId)
{
m_groupId = pair.first;
break;
}
}
if (m_groupId != -1)
break;
}
}
/* Get group selection via user */
if (m_groupId != -1)
{
if (allSongGroups.find(m_groupId) != allSongGroups.end())

View File

@@ -22,6 +22,7 @@ class BooBackendVoice : public IBackendVoice
struct VoiceCallback : boo::IAudioVoiceCallback
{
BooBackendVoice& m_parent;
void preSupplyAudio(boo::IAudioVoice& voice, double dt);
size_t supplyAudio(boo::IAudioVoice& voice, size_t frames, int16_t* data);
VoiceCallback(BooBackendVoice& parent) : m_parent(parent) {}
} m_cb;

View File

@@ -21,10 +21,10 @@ public:
};
private:
State m_phase = State::Attack; /**< Current envelope state */
double m_attackTime = 0.02; /**< Time of attack in seconds */
double m_attackTime = 0.0; /**< Time of attack in seconds */
double m_decayTime = 0.0; /**< Time of decay in seconds */
double m_sustainFactor = 1.0; /**< Evaluated sustain percentage */
double m_releaseTime = 0.02; /**< Time of release in seconds */
double m_releaseTime = 0.0; /**< Time of release in seconds */
double m_releaseStartFactor = 0.0; /**< Level at whenever release event occurs */
double m_curTime = 0.0; /**< Current time of envelope stage in seconds */
bool m_adsrSet = false;

View File

@@ -86,6 +86,7 @@ class Voice : public Entity
int32_t m_pitchWheelVal = 0; /**< Current resolved pitchwheel delta for control */
int32_t m_curPitch; /**< Current base pitch in cents */
bool m_pitchDirty = true; /**< m_curPitch has been updated and needs sending to voice */
bool m_needsSlew = false; /**< next _setTotalPitch will be slewed */
Envelope m_volAdsr; /**< Volume envelope */
double m_envelopeTime = -1.f; /**< time since last ENVELOPE command, -1 for no active volume-sweep */
@@ -137,7 +138,7 @@ class Voice : public Entity
void _doKeyOff();
void _macroKeyOff();
void _macroSampleEnd();
bool _advanceSample(int16_t& samp, int32_t& curPitch);
void _advanceSample(int16_t& samp);
void _setTotalPitch(int32_t cents, bool slew);
bool _isRecursivelyDead();
void _bringOutYourDead();
@@ -166,6 +167,10 @@ public:
Voice(Engine& engine, const AudioGroup& group, int groupId, int vid, bool emitter, Submix* smx);
Voice(Engine& engine, const AudioGroup& group, int groupId, ObjectId oid, int vid, bool emitter, Submix* smx);
/** Called before each supplyAudio invocation to prepare voice
* backend for possible parameter updates */
void preSupplyAudio(double dt);
/** Request specified count of audio frames (samples) from voice,
* internally advancing the voice stream */
size_t supplyAudio(size_t frames, int16_t* data);

View File

@@ -6,6 +6,12 @@
namespace amuse
{
void BooBackendVoice::VoiceCallback::preSupplyAudio(boo::IAudioVoice&,
double dt)
{
m_parent.m_clientVox.preSupplyAudio(dt);
}
size_t BooBackendVoice::VoiceCallback::supplyAudio(boo::IAudioVoice&,
size_t frames, int16_t* data)
{

View File

@@ -1679,6 +1679,72 @@ static std::vector<std::pair<SystemString, IntrusiveAudioGroupData>> LoadRS3(FIL
return ret;
}
static bool ValidateStarFoxAdvSongs(FILE* fp)
{
size_t endPos = FileLength(fp);
if (endPos > 2 * 1024 * 1024)
return false;
std::unique_ptr<uint8_t[]> data(new uint8_t[endPos]);
fread(data.get(), 1, endPos, fp);
const uint32_t* lengths = reinterpret_cast<const uint32_t*>(data.get());
size_t totalLen = 0;
int i=0;
for (; i<128 ; ++i)
{
uint32_t len = SBig(lengths[i]);
if (len == 0)
break;
totalLen += len;
totalLen = ((totalLen + 31) & ~31);
}
totalLen += (((i*4) + 31) & ~31);
return totalLen == endPos;
}
static std::vector<std::pair<SystemString, ContainerRegistry::SongData>> LoadStarFoxAdvSongs(FILE* midifp)
{
std::vector<std::pair<SystemString, ContainerRegistry::SongData>> ret;
size_t endPos = FileLength(midifp);
if (endPos > 2 * 1024 * 1024)
return {};
std::unique_ptr<uint8_t[]> data(new uint8_t[endPos]);
fread(data.get(), 1, endPos, midifp);
const uint32_t* lengths = reinterpret_cast<const uint32_t*>(data.get());
int i=0;
for (; i<128 ; ++i)
{
uint32_t len = SBig(lengths[i]);
if (len == 0)
break;
}
size_t sngCount = i;
size_t cur = (((sngCount*4) + 31) & ~31);
for (i=0; i<sngCount ; ++i)
{
uint32_t len = SBig(lengths[i]);
if (len == 0)
break;
SystemChar name[128];
SNPrintf(name, 128, _S("Song%u"), i);
std::unique_ptr<uint8_t[]> song(new uint8_t[len]);
memmove(song.get(), data.get() + cur, len);
ret.emplace_back(name, ContainerRegistry::SongData(std::move(song), len, -1, i));
cur += len;
cur = ((cur + 31) & ~31);
}
return ret;
}
ContainerRegistry::Type ContainerRegistry::DetectContainerType(const SystemChar* path)
{
FILE* fp;
@@ -2062,6 +2128,13 @@ ContainerRegistry::LoadSongs(const SystemChar* path)
return ret;
}
if (ValidateStarFoxAdvSongs(fp))
{
auto ret = LoadStarFoxAdvSongs(fp);
fclose(fp);
return ret;
}
fclose(fp);
}

View File

@@ -356,6 +356,15 @@ void Sequencer::setCtrlValue(uint8_t chan, uint8_t ctrl, int8_t val)
if (chan > 15)
return;
if (ctrl == 0x66)
{
printf("Loop Start\n");
}
else if (ctrl == 0x67)
{
printf("Loop End\n");
}
if (!m_chanStates[chan])
m_chanStates[chan].emplace(*this, chan);

View File

@@ -115,7 +115,7 @@ void Voice::_doKeyOff()
void Voice::_setTotalPitch(int32_t cents, bool slew)
{
//fprintf(stderr, "PITCH %d\n", cents);
//fprintf(stderr, "PITCH %d %d \n", cents, slew);
int32_t interval = cents - m_curSample->first.m_pitch * 100;
double ratio = std::exp2(interval / 1200.0);
m_sampleRate = m_curSample->first.m_sampleRate * ratio;
@@ -199,7 +199,7 @@ static void ApplyVolume(float vol, int16_t& samp)
samp *= VolumeLUT[int(vol * 65536)];
}
bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
void Voice::_advanceSample(int16_t& samp)
{
double dt;
@@ -223,7 +223,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
/* Apply total volume to sample using decibel scale */
ApplyVolume(l, samp);
return false;
return;
}
dt = 160.0 / m_sampleRate;
@@ -232,7 +232,6 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
}
m_voiceTime += dt;
bool refresh = false;
/* Process active envelope */
if (m_envelopeTime >= 0.0)
@@ -255,40 +254,6 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
/* Dynamically evaluate per-sample SoundMacro parameters */
float evalVol = m_state.m_volumeSel ? (m_state.m_volumeSel.evaluate(*this, m_state) / 2.f * m_curVol) : m_curVol;
bool panDirty = false;
if (m_state.m_panSel)
{
float evalPan = m_state.m_panSel.evaluate(*this, m_state);
if (evalPan != m_curPan)
{
m_curPan = evalPan;
panDirty = true;
}
}
if (m_state.m_spanSel)
{
float evalSpan = m_state.m_spanSel.evaluate(*this, m_state);
if (evalSpan != m_curSpan)
{
m_curSpan = evalSpan;
panDirty = true;
}
}
if (m_state.m_reverbSel)
{
float evalRev = m_state.m_reverbSel.evaluate(*this, m_state) / 2.f;
if (evalRev != m_curReverbVol)
{
m_curReverbVol = evalRev;
panDirty = true;
}
}
if (panDirty)
_setPan(m_curPan);
if (m_state.m_pitchWheelSel)
_setPitchWheel(m_state.m_pitchWheelSel.evaluate(*this, m_state));
/* Process user volume slew */
if (m_engine.m_ampMode == AmplitudeMode::PerSample)
{
@@ -351,8 +316,70 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
/* Apply total volume to sample using decibel scale */
ApplyVolume(m_nextLevel, samp);
}
uint32_t Voice::_GetBlockSampleCount(SampleFormat fmt)
{
switch (fmt)
{
default:
return 1;
case Voice::SampleFormat::DSP:
return 14;
case Voice::SampleFormat::N64:
return 64;
}
}
void Voice::preSupplyAudio(double dt)
{
/* Process SoundMacro; bootstrapping sample if needed */
bool dead = m_state.advance(*this, dt);
/* Process per-block evaluators here */
if (m_state.m_pedalSel)
{
bool pedal = m_state.m_pedalSel.evaluate(*this, m_state) >= 1.f;
if (pedal != m_sustained)
setPedal(pedal);
}
bool panDirty = false;
if (m_state.m_panSel)
{
float evalPan = m_state.m_panSel.evaluate(*this, m_state);
if (evalPan != m_curPan)
{
m_curPan = evalPan;
panDirty = true;
}
}
if (m_state.m_spanSel)
{
float evalSpan = m_state.m_spanSel.evaluate(*this, m_state);
if (evalSpan != m_curSpan)
{
m_curSpan = evalSpan;
panDirty = true;
}
}
if (m_state.m_reverbSel)
{
float evalRev = m_state.m_reverbSel.evaluate(*this, m_state) / 2.f;
if (evalRev != m_curReverbVol)
{
m_curReverbVol = evalRev;
panDirty = true;
}
}
if (panDirty)
_setPan(m_curPan);
if (m_state.m_pitchWheelSel)
_setPitchWheel(m_state.m_pitchWheelSel.evaluate(*this, m_state));
/* Process active pan-sweep */
bool refresh = false;
if (m_panningTime >= 0.f)
{
m_panningTime += dt;
@@ -383,7 +410,7 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
}
/* Calculate total pitch */
newPitch = m_curPitch;
int32_t newPitch = m_curPitch;
refresh |= m_pitchDirty;
m_pitchDirty = false;
if (m_portamentoTime >= 0.f)
@@ -423,20 +450,19 @@ bool Voice::_advanceSample(int16_t& samp, int32_t& newPitch)
refresh = true;
}
/* True if backend voice needs reconfiguration before next sample */
return refresh;
}
uint32_t Voice::_GetBlockSampleCount(SampleFormat fmt)
{
switch (fmt)
if (m_curSample && refresh)
{
default:
return 1;
case Voice::SampleFormat::DSP:
return 14;
case Voice::SampleFormat::N64:
return 64;
_setTotalPitch(newPitch + m_pitchSweep1 + m_pitchSweep2 + m_pitchWheelVal, m_needsSlew);
m_needsSlew = true;
}
if (dead && (!m_curSample || m_voxState == VoiceState::KeyOff) &&
m_sampleEndTrap.macroId == 0xffff &&
m_messageTrap.macroId == 0xffff &&
(!m_curSample || (m_curSample && m_volAdsr.isComplete())))
{
m_voxState = VoiceState::Dead;
m_backendVoice->stop();
}
}
@@ -445,23 +471,10 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
uint32_t samplesRem = samples;
size_t samplesProc = 0;
/* Process SoundMacro; bootstrapping sample if needed */
bool dead = m_state.advance(*this, samples / m_sampleRate);
/* Process per-block evaluators here */
if (m_state.m_pedalSel)
{
bool pedal = m_state.m_pedalSel.evaluate(*this, m_state) >= 1.f;
if (pedal != m_sustained)
setPedal(pedal);
}
if (m_curSample)
{
uint32_t blockSampleCount = _GetBlockSampleCount(m_curFormat);
uint32_t block;
int32_t curPitch = m_curPitch;
bool refresh = false;
bool looped = true;
while (looped && samplesRem)
@@ -517,7 +530,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
{
++samplesProc;
++m_curSamplePos;
refresh |= _advanceSample(data[i], curPitch);
_advanceSample(data[i]);
}
samplesRem -= decSamples;
@@ -582,7 +595,7 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
{
++samplesProc;
++m_curSamplePos;
refresh |= _advanceSample(data[i], curPitch);
_advanceSample(data[i]);
}
samplesRem -= decSamples;
@@ -598,22 +611,12 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
break;
}
}
if (refresh)
_setTotalPitch(curPitch + m_pitchSweep1 + m_pitchSweep2 + m_pitchWheelVal, true);
}
else
memset(data, 0, sizeof(int16_t) * samples);
if (dead && (!m_curSample || m_voxState == VoiceState::KeyOff) &&
m_sampleEndTrap.macroId == 0xffff &&
m_messageTrap.macroId == 0xffff &&
(!m_curSample || (m_curSample && m_volAdsr.isComplete())))
{
if (m_voxState == VoiceState::Dead)
m_curSample = nullptr;
m_voxState = VoiceState::Dead;
m_backendVoice->stop();
}
return samples;
}
@@ -795,6 +798,7 @@ void Voice::startSample(int16_t sampId, int32_t offset)
m_pitchDirty = true;
_setPitchWheel(m_curPitchWheel);
m_backendVoice->resetSampleRate(m_curSample->first.m_sampleRate);
m_needsSlew = false;
int32_t numSamples = m_curSample->first.m_numSamples & 0xffffff;
if (offset)
@@ -1001,7 +1005,7 @@ void Voice::setPitchSweep1(uint8_t times, int16_t add)
{
m_pitchSweep1 = 0;
m_pitchSweep1It = 0;
m_pitchSweep1Times = times * 160;
m_pitchSweep1Times = times;
m_pitchSweep1Add = add;
}
@@ -1009,7 +1013,7 @@ void Voice::setPitchSweep2(uint8_t times, int16_t add)
{
m_pitchSweep2 = 0;
m_pitchSweep2It = 0;
m_pitchSweep2Times = times * 160;
m_pitchSweep2Times = times;
m_pitchSweep2Add = add;
}