mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
741 lines
20 KiB
C++
741 lines
20 KiB
C++
/*
|
|
* $Logfile: /DescentIII/Main/music/sequencer.cpp $
|
|
* $Revision: 35 $
|
|
* $Date: 4/09/99 12:04p $
|
|
* $Author: Samir $
|
|
*
|
|
* Event driven music system
|
|
*
|
|
* $Log: /DescentIII/Main/music/sequencer.cpp $
|
|
*
|
|
* 35 4/09/99 12:04p Samir
|
|
* take out error messages (mprintfs) for stream load failures.
|
|
*
|
|
* 34 4/01/99 4:50p Matt
|
|
* Took out Warning() function, chaning those calls to mprintf()
|
|
*
|
|
* 33 3/18/99 10:13a Samir
|
|
* msuic update.
|
|
*
|
|
* 32 3/03/99 5:08p Samir
|
|
* added slew of debug code: hopefully the library will be revamped after
|
|
* OEM.
|
|
*
|
|
* 31 3/03/99 3:43a Samir
|
|
* moved mprintfs for debugging.
|
|
*
|
|
* 30 3/02/99 1:18p Samir
|
|
* fixes to prevent bad filenames from crashing system.
|
|
*
|
|
* 29 3/01/99 5:01a Samir
|
|
* fixed bug when no pending or active song, it would still try to start a
|
|
* pending song.
|
|
*
|
|
* 28 2/28/99 6:35p Samir
|
|
* fixed streaming bugs for very small samples.
|
|
*
|
|
* 27 2/27/99 8:23p Samir
|
|
* fixes to music system to act nicely to sudden and frequent region
|
|
* changes.
|
|
*
|
|
* 26 2/27/99 6:51p Samir
|
|
* added code for music tester to display current stream and loop/region.
|
|
*
|
|
* 25 2/27/99 5:13p Nate
|
|
* Samir: fixes
|
|
*
|
|
* 24 2/27/99 4:37p Samir
|
|
* return name of loop currently playing.
|
|
*
|
|
* 23 2/26/99 5:26p Samir
|
|
* fixes to streaming audio to reflect fix in direct sound mixer.
|
|
*
|
|
* 22 2/22/99 3:23p Luke
|
|
* upped size of music buffers
|
|
*
|
|
* 21 2/16/99 12:09p Samir
|
|
* immediate switches open new stream object.
|
|
*
|
|
* 20 1/28/99 2:22p Samir
|
|
* simplified music system for D3.
|
|
*
|
|
* 19 12/13/98 6:51p Samir
|
|
* enhancements.
|
|
*
|
|
* 18 12/11/98 6:05p Samir
|
|
* fixed looping bug (didn't set loop count!)
|
|
*
|
|
* 17 12/11/98 4:02p Samir
|
|
* clean theme changes.
|
|
*
|
|
* 16 12/10/98 10:12a Samir
|
|
* uses newer streaming audio library
|
|
*
|
|
* 15 12/07/98 11:45a Samir
|
|
* hacks to get music system mostly working in DS_8. Will change this
|
|
* system so it's a lot cleaner after music demo.
|
|
*
|
|
* 14 12/03/98 12:48p Samir
|
|
* speed up sequencer so that gap between samples isn't too big.
|
|
*
|
|
* 13 11/20/98 5:20p Samir
|
|
* added a bunch of high level scripting commands.
|
|
*
|
|
* 12 11/16/98 4:15p Samir
|
|
* fadeouts.
|
|
*
|
|
* 11 11/13/98 2:27p Samir
|
|
* new music system.
|
|
*
|
|
* 10 8/10/98 5:53p Samir
|
|
* improved switching between streams and basic background/combat music.
|
|
*
|
|
* 9 7/30/98 7:33p Jeff
|
|
* fixed bug passing NULL to reset.
|
|
*
|
|
* 8 7/28/98 5:43p Samir
|
|
* reorg of music system.
|
|
*
|
|
* 7 7/24/98 5:20p Samir
|
|
* first real music checkin.
|
|
*
|
|
* 6 7/08/98 6:26p Samir
|
|
* took out obsolete code.
|
|
*
|
|
* 5 2/15/98 7:12p Chris
|
|
* More improvements to the sound lib
|
|
*
|
|
* 4 1/05/98 3:54p Chris
|
|
* Added ambient and explosion sounds
|
|
*
|
|
* 3 12/31/97 2:58a Chris
|
|
* Another major revision to the SoundLib. This cleaned up the code after
|
|
* removing the direct sound secondary buffers.
|
|
*
|
|
* 2 12/10/97 4:47p Chris
|
|
* Revision 1.0 of new sound library (no hardware -- uses primary buffer
|
|
* streaming)
|
|
*
|
|
* 3 5/29/97 3:58p Samir
|
|
* Works with some very small pauses.
|
|
*
|
|
* 2 5/23/97 4:34p Samir
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "music.h"
|
|
#include "musiclib.h"
|
|
#include "ssl_lib.h"
|
|
#include "soundload.h"
|
|
#include "textaux.h"
|
|
#include "pserror.h"
|
|
#include "ddio.h"
|
|
#include "Macros.h"
|
|
#include "InfFile.h"
|
|
#include "streamaudio.h"
|
|
#include "mem.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
//#include "samirlog.h"
|
|
#define LOGFILE(_s)
|
|
|
|
OutrageMusicSeq::OutrageMusicSeq() {
|
|
m_sequencer_run = false;
|
|
m_sequencer_init = false;
|
|
m_str_buffer = NULL;
|
|
m_ins_buffer = NULL;
|
|
m_curregion = -1;
|
|
m_pending_song = m_active_song = m_playing_song = NULL;
|
|
}
|
|
|
|
OutrageMusicSeq::~OutrageMusicSeq() { OutrageMusicSeq::Shutdown(); }
|
|
|
|
// takes a OMS theme file.
|
|
bool OutrageMusicSeq::Init(const char *theme_file) {
|
|
// reset streams
|
|
m_dominant_strm = 0;
|
|
m_timer = 0.0f;
|
|
|
|
if (theme_file[0] == 0) {
|
|
return false;
|
|
}
|
|
|
|
Stop();
|
|
|
|
// initialize memory buffers
|
|
m_ins_buffer = (music_ins *)mem_malloc(sizeof(music_ins) * MAX_MUSIC_INSTRUCTIONS);
|
|
m_str_buffer = (char *)mem_malloc(MAX_MUSIC_STRLEN);
|
|
m_ins_curptr = m_ins_buffer;
|
|
m_str_curptr = m_str_buffer;
|
|
m_str_curptr[0] = 0;
|
|
|
|
// initialize music lists
|
|
m_music_list.free();
|
|
m_tracklist.init(64);
|
|
m_pending_song = m_active_song = m_playing_song = NULL;
|
|
m_output_q.flush();
|
|
m_curregion = -1;
|
|
|
|
OutrageMusicSeq::SetVolume(1.0f);
|
|
m_sequencer_init = true;
|
|
|
|
return LoadTheme(theme_file);
|
|
}
|
|
|
|
void OutrageMusicSeq::Shutdown() {
|
|
if (!m_sequencer_init)
|
|
return;
|
|
|
|
Stop();
|
|
|
|
// free music lists.
|
|
FreeList();
|
|
m_tracklist.free();
|
|
|
|
// free allocated buffers
|
|
mem_free(m_ins_buffer);
|
|
mem_free(m_str_buffer);
|
|
|
|
// free streams
|
|
for (int i = 0; i < OMS_NUM_STRM; i++)
|
|
m_strm[i].Reset(this);
|
|
|
|
m_playing_song = NULL;
|
|
m_sequencer_init = false;
|
|
}
|
|
|
|
// starts the sequencer (usually at the beginning of a level)
|
|
void OutrageMusicSeq::Start() {
|
|
if (IsSequencerRunning() || !m_sequencer_init)
|
|
return;
|
|
|
|
int i;
|
|
|
|
m_sequencer_run = true;
|
|
m_dominant_strm = 0;
|
|
|
|
m_timer = 0.0f;
|
|
|
|
for (i = 0; i < N_MUSIC_REGS; i++) {
|
|
m_registers[i] = 0;
|
|
}
|
|
|
|
mprintf((0, "Music system on.\n"));
|
|
}
|
|
|
|
// stops the sequencer, flushes events
|
|
void OutrageMusicSeq::Stop() {
|
|
if (!IsSequencerRunning())
|
|
return;
|
|
|
|
int i;
|
|
|
|
mprintf((0, "Music system off.\n"));
|
|
m_sequencer_run = false;
|
|
|
|
for (i = 0; i < OMS_NUM_STRM; i++) {
|
|
m_strm[i].Reset(this);
|
|
}
|
|
}
|
|
|
|
// set volume of sequencer
|
|
void OutrageMusicSeq::SetVolume(float vol) {
|
|
int i;
|
|
|
|
ASSERT(vol >= 0.0f && vol <= 1.0f);
|
|
m_mastervol = vol;
|
|
|
|
for (i = 0; i < OMS_NUM_STRM; i++)
|
|
m_strm[i].SetVolume(m_mastervol);
|
|
}
|
|
|
|
#define START_PENDING_SONG() \
|
|
do { \
|
|
ASSERT(m_pending_song); \
|
|
if (m_active_song) { \
|
|
m_pending_song->strm = m_active_song->strm; \
|
|
} \
|
|
m_active_song = m_pending_song; \
|
|
if (m_active_song) { \
|
|
m_active_song->stream_idle = false; \
|
|
m_active_song->request_stop = false; \
|
|
} \
|
|
m_pending_song = NULL; \
|
|
} while (0)
|
|
|
|
// runs a frame of input.
|
|
void OutrageMusicSeq::Frame(float frame_time) {
|
|
bool start_pending_song = false;
|
|
int i;
|
|
|
|
// run check.
|
|
if (!m_sequencer_run)
|
|
return;
|
|
|
|
// close all streams that aren't the dominant one and have stopped playing
|
|
for (i = 0; i < OMS_NUM_STRM; i++) {
|
|
if ((&m_strm[i]) != (&m_strm[m_dominant_strm])) {
|
|
if (m_strm[i].m_stream.State() == STRM_STOPPED) {
|
|
m_strm[i].m_stream.Close();
|
|
}
|
|
}
|
|
}
|
|
|
|
// determine when to start song if a song is pending.
|
|
if (!m_active_song && m_pending_song) {
|
|
start_pending_song = true;
|
|
}
|
|
|
|
if (m_pending_song) {
|
|
if (m_pending_song->immediate_switch == true) {
|
|
start_pending_song = true;
|
|
} else if (m_active_song) {
|
|
if (m_active_song->stream_idle) {
|
|
// this will transfer the current song's steam to the pending one, so the
|
|
// ExecScript function can manage these streams.
|
|
start_pending_song = true;
|
|
} else if (!m_active_song->request_stop) {
|
|
m_active_song->request_stop = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (start_pending_song) {
|
|
mprintf((0, "MUSIC:Starting pending song.\n"));
|
|
LOGFILE((_logfp, "MUSIC:Starting pending song.\n"));
|
|
START_PENDING_SONG();
|
|
}
|
|
|
|
// execute song code
|
|
ExecScript(m_active_song);
|
|
|
|
// process streams, starting at dominant stream.
|
|
// this is vital to ensure that the dominant stream's commands are executed before any
|
|
// other streams.
|
|
// i = m_dominant_strm;
|
|
// do
|
|
// {
|
|
// m_strm[i].Process(frame_time);
|
|
// i++;
|
|
// if (i == OMS_NUM_STRM) i = 0;
|
|
// }
|
|
// while (i != m_dominant_strm);
|
|
|
|
m_timer += frame_time;
|
|
}
|
|
|
|
// music kernal.
|
|
void OutrageMusicSeq::ExecScript(music_stream *strm) {
|
|
if (!strm)
|
|
return;
|
|
|
|
// get command
|
|
next_ins:
|
|
music_ins *cur_ins = &strm->ins[strm->ip];
|
|
ubyte cmd = cur_ins->cmd;
|
|
tMusicVal val = cur_ins->opr.num;
|
|
char *str = cur_ins->opr.str;
|
|
const char *name;
|
|
|
|
// goto next instruction.
|
|
strm->ip++;
|
|
|
|
// mprintf((0, "%d ", cmd));
|
|
AudioStream *stream = &strm->strm->m_stream;
|
|
|
|
// execute opcodes.
|
|
// if (strm->last_ip != strm->ip) {
|
|
// LOGFILE((_logfp, "ins=%d\n", cmd));
|
|
// }
|
|
strm->last_ip = strm->ip;
|
|
|
|
switch (cmd) {
|
|
case OMFCMD_PLAY:
|
|
name = m_tracklist.get(strm->ln_reg);
|
|
if (name) {
|
|
// close this song's stream.
|
|
bool err = false;
|
|
|
|
strm->old_strm = strm->strm;
|
|
|
|
strm->error = false;
|
|
|
|
if (strm->immediate_switch) {
|
|
// we start playing the current stream immediately.
|
|
stream->Close();
|
|
m_dominant_strm = DOMINANT_STRM_ADJUST();
|
|
// mprintf((0, "MUSIC: Starting stream with %s on channel %d.\n", name, m_dominant_strm));
|
|
LOGFILE((_logfp, "MUSIC: Starting stream with %s on channel %d.\n", name, m_dominant_strm));
|
|
strm->strm = &m_strm[m_dominant_strm];
|
|
stream = &strm->strm->m_stream;
|
|
err = stream->Open(name);
|
|
} else {
|
|
m_dominant_strm = DOMINANT_STRM_ADJUST();
|
|
// mprintf((0, "MUSIC: Preparing stream with %s on channel %d.\n", name, m_dominant_strm));
|
|
LOGFILE((_logfp, "MUSIC: Preparing stream with %s on channel %d.\n", name, m_dominant_strm));
|
|
strm->strm = &m_strm[m_dominant_strm];
|
|
stream = &strm->strm->m_stream;
|
|
err = stream->Open(name);
|
|
// stream->Open(name, STRM_OPNF_GRADUAL);
|
|
}
|
|
|
|
// skip instructions until error is cleared.
|
|
if (!err) {
|
|
// mprintf((0, "MUSIC: Error opening stream %s on channel %d.\n", name, m_dominant_strm));
|
|
LOGFILE((_logfp, "MUSIC: Error opening stream %s on channel %d.\n", name, m_dominant_strm));
|
|
strm->error = true;
|
|
}
|
|
|
|
stream->SetLoopCount(strm->p_reg);
|
|
stream->SetVolume(m_mastervol);
|
|
strm->stream_idle = false;
|
|
} else {
|
|
mprintf((0, "OMS: Stream was not found in track list.\n"));
|
|
}
|
|
|
|
strm->pending_loop_name = name;
|
|
break;
|
|
|
|
case OMFCMD_MPLAY:
|
|
if (strm->immediate_switch || strm->error) {
|
|
strm->immediate_switch = false;
|
|
} else if (!stream->IsReady()) {
|
|
strm->ip--;
|
|
break;
|
|
} else if (strm->old_strm) {
|
|
if (strm->old_strm->m_stream.State() != STRM_STOPPED && strm->old_strm->m_stream.State() != STRM_INVALID) {
|
|
strm->ip--;
|
|
break;
|
|
}
|
|
}
|
|
strm->loop_name = strm->pending_loop_name;
|
|
m_playing_song = strm;
|
|
|
|
if (!strm->error) {
|
|
strm->error = !(stream->Play());
|
|
}
|
|
|
|
if (!strm->error) {
|
|
// mprintf((0, "MUSIC: playing %s.\n", strm->loop_name));
|
|
LOGFILE((_logfp, "MUSIC: playing %s.\n", strm->loop_name));
|
|
LOGFILE((_logfp, "MUSIC: state of played stream is %d.\n", strm->loop_name, stream->State()));
|
|
} else {
|
|
// mprintf((0, "MUSIC: Error playing %s.\n", strm->loop_name));
|
|
LOGFILE((_logfp, "MUSIC: Error playing %s.\n", strm->loop_name));
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_WAIT:
|
|
Int3(); // flaky, shouldn't be used anymore.
|
|
strm->ip--;
|
|
if (val == 1) {
|
|
if (strm->strm->m_valid_result && strm->strm->m_result.cmd == OMS_STRM_STOP) {
|
|
// wait till stream has finished to continue.
|
|
strm->ip++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_LCMP:
|
|
strm->c_reg = val;
|
|
break;
|
|
|
|
case OMFCMD_LLPT:
|
|
strm->ln_reg = str;
|
|
break;
|
|
|
|
case OMFCMD_LPLC:
|
|
strm->p_reg = val;
|
|
break;
|
|
|
|
case OMFCMD_SETI:
|
|
strm->i_reg = val;
|
|
break;
|
|
|
|
case OMFCMD_INCI:
|
|
strm->i_reg++;
|
|
break;
|
|
|
|
case OMFCMD_IFI:
|
|
strm->ifi_block = (strm->i_reg == val) ? true : false;
|
|
if (!strm->ifi_block) {
|
|
// skip ifi block.
|
|
while (strm->ins[strm->ip].cmd != OMFCMD_ENDIFI)
|
|
strm->ip++;
|
|
strm->ip++;
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_ENDIFI:
|
|
strm->ifi_block = false;
|
|
break;
|
|
|
|
case OMFCMD_COMPARE: {
|
|
tMusicVal reg1 = strm->c_reg;
|
|
tMusicVal reg2 = m_registers[val];
|
|
strm->b_reg = (reg2 - reg1);
|
|
break;
|
|
}
|
|
|
|
case OMFCMD_GOTO:
|
|
// simply set IP.
|
|
strm->ip = val;
|
|
break;
|
|
|
|
case OMFCMD_BLT:
|
|
if (strm->b_reg < 0) {
|
|
strm->ip = val;
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_BGT:
|
|
if (strm->b_reg > 0) {
|
|
strm->ip = val;
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_BEQ:
|
|
if (strm->b_reg == 0) {
|
|
strm->ip = val;
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_BNIF:
|
|
if (stream->ReadAheadFinishedLoop() || strm->error) {
|
|
oms_q_evt evt;
|
|
evt.cmd = OMS_EVT_LOOPENDING;
|
|
evt.parm.i = strm->type;
|
|
m_output_q.send(evt);
|
|
if (!strm->error) {
|
|
strm->ip--; // repeat this instruction again
|
|
}
|
|
} else if (!strm->request_stop) {
|
|
if (stream->ReadAhead()) {
|
|
strm->ip = val;
|
|
} else if (stream->State() != STRM_STOPPING && stream->State() != STRM_STOPPED) {
|
|
strm->ip = val;
|
|
}
|
|
} else {
|
|
stream->Stop(true); // soft stop on end of stream.
|
|
if (strm->request_stop) {
|
|
strm->stream_idle = true;
|
|
strm->request_stop = false;
|
|
mprintf((0, "MUSIC: Processed stop request.\n"));
|
|
LOGFILE((_logfp, "MUSIC: Processed stop request.\n"));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OMFCMD_ENDSECTION: {
|
|
strm->ip--;
|
|
if (stream->State() == STRM_STOPPED) {
|
|
oms_q_evt evt;
|
|
strm->ip++;
|
|
evt.cmd = OMS_EVT_SONGENDED;
|
|
evt.parm.i = strm->type;
|
|
m_output_q.send(evt);
|
|
strm->stream_idle = true;
|
|
m_active_song = NULL;
|
|
m_playing_song = NULL;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// okay, ifi_block is only really useful to determine if we're going to execute consecutive instructions
|
|
// note that even if we turn off ifi_block, this doesn't stop instructions from running inside the ifi_block
|
|
// but it does stop consecutive instructions.
|
|
// the actual decision to run the instructions in an ifi_block depends on the initial check.
|
|
if (cmd != OMFCMD_ENDSECTION && cmd != OMFCMD_PLAY && cmd != OMFCMD_MPLAY && cmd < OMFCMD_BRANCHING) {
|
|
goto next_ins;
|
|
} else {
|
|
strm->ifi_block = false;
|
|
}
|
|
}
|
|
|
|
// start a song, stopping the old either cleanly (on measure) or abruptly.
|
|
void OutrageMusicSeq::StartSong(int song, bool clean_switch) {
|
|
if (m_curregion >= 0) {
|
|
m_pending_song = GetSong(m_curregion, (short)song);
|
|
} else {
|
|
m_pending_song = NULL;
|
|
}
|
|
|
|
if (m_pending_song) {
|
|
m_pending_song->request_stop = false;
|
|
m_pending_song->immediate_switch = !clean_switch;
|
|
m_pending_song->strm = &m_strm[m_dominant_strm];
|
|
}
|
|
}
|
|
|
|
// stops song, cold.
|
|
void OutrageMusicSeq::StopSong() {
|
|
if (m_active_song) {
|
|
m_active_song = NULL;
|
|
m_playing_song = NULL;
|
|
}
|
|
m_strm[m_dominant_strm].m_stream.Close();
|
|
}
|
|
|
|
// pauses
|
|
void OutrageMusicSeq::Pause() {
|
|
int i;
|
|
|
|
for (i = 0; i < OMS_NUM_STRM; i++) {
|
|
m_strm[i].m_stream.Pause();
|
|
}
|
|
}
|
|
|
|
void OutrageMusicSeq::Resume() {
|
|
int i;
|
|
|
|
for (i = 0; i < OMS_NUM_STRM; i++) {
|
|
m_strm[i].m_stream.Resume();
|
|
}
|
|
}
|
|
|
|
// get and set user defined (theme file) parameters
|
|
void OutrageMusicSeq::SetRegister(int parm, tMusicVal val) {
|
|
ASSERT(parm >= 0 && parm < N_MUSIC_REGS);
|
|
m_registers[parm] = val;
|
|
}
|
|
|
|
tMusicVal OutrageMusicSeq::GetRegister(int parm) {
|
|
ASSERT(parm >= 0 && parm < N_MUSIC_REGS);
|
|
return m_registers[parm];
|
|
}
|
|
|
|
// memory management
|
|
OutrageMusicSeq::music_ins *OutrageMusicSeq::alloc_and_copy_ins(int len, const music_ins *ins) {
|
|
// copy instructions to static buffer and return a pointer to it
|
|
if ((m_ins_curptr + len) > (m_ins_buffer + MAX_MUSIC_INSTRUCTIONS)) {
|
|
Int3();
|
|
return NULL;
|
|
} else {
|
|
memcpy(m_ins_curptr, ins, len * sizeof(music_ins));
|
|
m_ins_curptr += len;
|
|
return (m_ins_curptr - len);
|
|
}
|
|
}
|
|
|
|
char *OutrageMusicSeq::alloc_and_copy_str(const char *str) {
|
|
// copy string to static buffer and return a pointer to it
|
|
int slen = strlen(str) + 1;
|
|
if ((m_str_curptr + slen) > (m_str_buffer + MAX_MUSIC_STRLEN)) {
|
|
Int3();
|
|
return NULL;
|
|
} else {
|
|
strcpy(m_str_curptr, str);
|
|
m_str_curptr += slen;
|
|
return (m_str_curptr - slen);
|
|
}
|
|
}
|
|
|
|
// Music list management
|
|
OutrageMusicSeq::music_stream *OutrageMusicSeq::AddToList(short region, short theme_type, int len,
|
|
const music_ins *ins) {
|
|
tListNode<music_stream> *node = new tListNode<OutrageMusicSeq::music_stream>;
|
|
|
|
// create list item
|
|
node->t.region = region;
|
|
node->t.type = theme_type;
|
|
node->t.ins = alloc_and_copy_ins(len, ins);
|
|
if (!node->t.ins) {
|
|
delete node;
|
|
return NULL;
|
|
}
|
|
|
|
// link it in.
|
|
m_music_list.link(node);
|
|
|
|
return &node->t;
|
|
}
|
|
|
|
void OutrageMusicSeq::FreeList() {
|
|
tListNode<music_stream> *node;
|
|
|
|
while (node = m_music_list.start()) {
|
|
node = m_music_list.unlink();
|
|
delete[] node;
|
|
}
|
|
|
|
m_music_list.free();
|
|
}
|
|
|
|
OutrageMusicSeq::music_stream *OutrageMusicSeq::GetSong(short region, short theme_type) {
|
|
tListNode<music_stream> *node = m_music_list.start();
|
|
music_stream *strm = NULL;
|
|
int i;
|
|
|
|
for (i = 0; i < m_music_list.length(); node = m_music_list.next(), i++) {
|
|
if (region == node->t.region) {
|
|
if (theme_type == node->t.type) {
|
|
strm = &node->t;
|
|
}
|
|
|
|
if (strm) {
|
|
strm->request_stop = false;
|
|
strm->immediate_switch = false;
|
|
strm->ip = 0;
|
|
strm->b_reg = 0;
|
|
strm->c_reg = 0;
|
|
strm->ln_reg = 0;
|
|
strm->p_reg = 0;
|
|
strm->i_reg = 0;
|
|
strm->ifi_block = false;
|
|
strm->stream_idle = true;
|
|
strm->strm = NULL;
|
|
strm->old_strm = NULL;
|
|
strm->loop_name = NULL;
|
|
strm->pending_loop_name = NULL;
|
|
strm->last_ip = -1;
|
|
strm->error = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return strm;
|
|
}
|
|
|
|
//@@void OutrageMusicSeq::seqSilence()
|
|
//@@{
|
|
//@@// silence all streams.
|
|
//@@ int init_strm = m_dominant_strm;
|
|
//@@ do
|
|
//@@ {
|
|
//@@ // request switch to dominant stream when measure is complete.
|
|
//@@ m_strm[m_dominant_strm].SEND_STRM_FADEOUT(4.0f);
|
|
//@@ m_strm[m_dominant_strm].SEND_STRM_STOP();
|
|
//@@ m_strm[m_dominant_strm].SEND_STRM_FREE();
|
|
//@@ m_dominant_strm = DOMINANT_STRM_ADJUST();
|
|
//@@ }
|
|
//@@ while (init_strm != m_dominant_strm);
|
|
//@@}
|
|
|
|
void OutrageMusicSeq::SetCurrentRegion(short region) { m_curregion = region; }
|
|
|
|
short OutrageMusicSeq::GetCurrentRegion() const { return m_curregion; }
|
|
|
|
// get current loop playing
|
|
const char *OutrageMusicSeq::GetCurrentLoopName(int *count) {
|
|
if (m_playing_song) {
|
|
*count = m_playing_song->strm->m_stream.GetLoopCount();
|
|
return m_playing_song->loop_name;
|
|
}
|
|
|
|
*count = 0;
|
|
return NULL;
|
|
}
|
|
|
|
// gets current region PLAYING, not PENDING like above.
|
|
short OutrageMusicSeq::GetPlayingRegion() const {
|
|
if (m_playing_song) {
|
|
return m_playing_song->region;
|
|
}
|
|
|
|
return -1;
|
|
}
|