protected bool StartSoundInternal(int sound, int offset = 0)
{
// Do not start a sound if it is already set to start on an ImTrigger
// event. This fixes carnival music problems where a sound has been set
// to trigger at the right time, but then is started up immediately
// anyway, only to be restarted later when the trigger occurs.
//
// However, we have to make sure the sound with the trigger is actually
// playing, otherwise the music may stop when Sam and Max are thrown
// out of Bumpusville, because entering the mansion sets up a trigger
// for a sound that isn't necessarily playing. This is somewhat related
// to bug #780918.
foreach (var trigger in _snm_triggers)
{
if (trigger.Sound != 0 && trigger.Id != 0 && trigger.Command[0] == 8 && trigger.Command[1] == sound && GetSoundStatusInternal(trigger.Sound, true) != 0)
return false;
}
var ptr = FindStartOfSound(sound);
if (ptr == null)
{
Debug.WriteLine("IMuseInternal::startSound(): Couldn't find sound {0}", sound);
return false;
}
// Check which MIDI driver this track should use.
// If it's NULL, it ain't something we can play.
var driver = GetBestMidiDriver(sound);
if (driver == null)
return false;
// If the requested sound is already playing, start it over
// from scratch. This was originally a hack to prevent Sam & Max
// iMuse messiness while upgrading the iMuse engine, but it
// is apparently necessary to deal with fade-and-restart
// race conditions that were observed in MI2. Reference
// Bug #590511 and Patch #607175 (which was reversed to fix
// an FOA regression: Bug #622606).
var player = FindActivePlayer(sound);
if (player == null)
{
ptr = FindStartOfSound(sound, ChunkType.MDhd);
int size = 128;
if (ptr != null)
{
using (var br = new BinaryReader(new MemoryStream(ptr)))
{
br.BaseStream.Seek(4, SeekOrigin.Begin);
var tmp = br.ReadUInt32BigEndian();
size = tmp != 0 && ptr[10] != 0 ? ptr[10] : 128;
}
}
player = AllocatePlayer((byte)size);
}
if (player == null)
return false;
// WORKAROUND: This is to work around a problem at the Dino Bungie
// Memorial.
//
// There are three pieces of music involved here:
//
// 80 - Main theme (looping)
// 81 - Music when entering Rex's and Wally's room (not looping)
// 82 - Music when listening to Rex or Wally
//
// When entering, tune 81 starts, tune 80 is faded down (not out) and
// a trigger is set in tune 81 to fade tune 80 back up.
//
// When listening to Rex or Wally, tune 82 is started, tune 81 is faded
// out and tune 80 is faded down even further.
//
// However, when tune 81 is faded out its trigger will cause tune 80 to
// fade back up, resulting in two tunes being played simultaneously at
// full blast. It's no use trying to keep tune 81 playing at volume 0.
// It doesn't loop, so eventually it will terminate on its own.
//
// I don't know how the original interpreter handled this - or even if
// it handled it at all - but it looks like sloppy scripting to me. Our
// workaround is to clear the trigger if the player listens to Rex or
// Wally before tune 81 has finished on its own.
if (_game_id == GameId.SamNMax && sound == 82 && GetSoundStatusInternal(81, false) != 0)
ImClearTrigger(81, 1);
player.Clear();
player.SetOffsetNote(offset);
return player.StartSound(sound, driver);
}