Open main menu

iMuse

iMuse is the system used for the music. It main feature is to allow perfect integration of the music; with some talent, the game music can appear as a continuous soundtrack to the player.

SCUMM interface

Imuse is a subsystem of the SCUMM engine with its own set of commands. From a SCUMM script the following functions are avaible:

  • startSound(snd)
  • stopSound(snd)
  • startMusic(m)
  • isSoundRunning(snd)
  • soundKludge([cmd_list])

As you can see, that is pretty spartan: all the power is in the soundKludge function. This will need some pretty good abstraction in the compiler, probably by adding a block similar to inline asm in C.

Command list

  • 0x0006 : imSetMasterVolume(volume)
  volume      : [0-127]
  • 0x0007 : imGetMasterVolume()
  • 0x0008 : imStartSound(sound)
  • 0x0009 : imStopSound(sound)
  • 0x000A : imStopAllSounds() ???
  • 0x000B : imStopAllSounds()
  • 0x000C : imPlayerSet(player, ???, cmd, params ...)

Used in S&M

  • 0x000D : imGetSoundStatus(sound)

sound == -1 returns the first active sound

  • 0x000E : imFadeSound(player, ????, fader_p1, fader_p2, fader_p3)

S&M only ?

  • 0x000F : imMaybeHook(player, ????, param)

S&M

  • 0x0010 : imSetVolchan(sound,volchan)
  • 0x0011 : imSetChannelVolume(chan,volume)

In S&M: set/clear trigger

  • 0x0012 : imSetVolchanEntry(volchan,val)

S&M: ImCheckTrigger

  • 0x0013 : imClearTrigger(a,b)
  • 0x0100 : imPlayerGetParam(player,param,chan)

In DOTT this is often called with only 2 args, in that case it seems to default to chan=0. S&M: Beat suff

  • 0x0101 : imPlayerSetPriority(player,prio)
  • 0x0102 : imPlayerSetVolume(player,volume)
  volume      : [0:127]
  • 0x0103 : imPlayerSetPan(player,pan)
  • 0x0104 : imPlayerSetTranspose(player,relative,val)
  val         : [-24:24]
  • 0x0105 : imPlayerSetDetune(player,detune)
  • 0x0106 : imPlayerSetSpeed(player,speed)
  • 0x0107 : imPlayerJump(player,track,beat,tick)
  • 0x0108 : imPlayerScan(player,toTrack,toBeat,toTick)
  • 0x0109 : imPlayerSetLoop(player,count,toBeat,toTick,fromBeat,fromTick)
  • 0x010A : imPlayerClearLoop(player)
  • 0x010B : imPlayerSetOnOff(player,chan,status)
  • 0x010C : imPlayerSetHook(player,type,value,chan)
  • 0x010D : imPlayerFade(player,target,time)
  • 0x010E : imQueueTrigger(a,b)
  • 0x010F : imQueueCommand(cmd,arg1,arg2,arg3,arg4,arg5,arg6)
  • 0x0110 : imClearQueue()
  • 0x0111 : ??? Live MIDI ON
  • 0x0112 : ??? Live MIDI OFF
  • 0x0113 : imPlayerGetParam(player,param,chan)
  • 0x0114 : imPlayerSetHook(player,type,value,chan)
  • 0x0115 : ???
  • 0x0116 : imPlayerSetVolume(player,part,vol)
  • 0x0117 : imQueryQueue(param)
    • param:
      • 0: trigger count
      • 1: last trigger type
      • 2: last trigger sound
  • 0x0118 : ???

Player parameters

  • 0x00: priority
  • 0x01: volume
  • 0x02: pan
  • 0x03: transpose
  • 0x04: detune
  • 0x05: speed
  • 0x06: track index
  • 0x07: beat index
  • 0x08: tick index
  • 0x09: loop counter
  • 0x0A: loop to beat
  • 0x0B: loop to tick
  • 0x0C: loop from tick
  • 0x0D: loop from tick
  • 0x0E: part on
  • 0x0F: part vol
  • 0x10: part instrument
  • 0x11: part transpose
  • 0x12: jump hook
  • 0x13: transpose hook
  • 0x14: part onoff hook
  • 0x15: part volume hook
  • 0x16: part program hook
  • 0x17: part transpose hook

Hook types

  • 0x00: jump
  • 0x01: transpose
  • 0x02: chan on/off (0x0F == all)
  • 0x03: chan volume (0x0F == all)
  • 0x04: chan part program
  • 0x05: chan transpose

MIDI SysEx

The MIDI data fed to iMUSE can contain (and to some extent needs) some special SysEx commands. The manufacturer ID 0x7D is used for these SysExes and the first byte indicates the command.

In the SysEx data, only the first 7 bits are significant (value in the 0x80-0xFF range are used for real-time messages among other things), so values larger than 7 bits use 1 nibble per byte in big endian order (most significant nibble first). In the following descriptions, each line corresponds to one or more bytes of data.

The relevant code in ScummVM 0.9 is in engines/scumm/imuse/sysex_scumm.cpp and engines/scumm/imuse/imuse_player.cpp.

  • 0x00: Allocate new part
  part        : 4
  unknown     : 7
  flags       : 2 bit 0 turn the part on/off
                  bit 1 turn the reverb on/off
  priority    : 7
  volume      : 8
  pan         : 8
  flags2      : 7 bit 3 set percussion mode
  pitchbend   : 8
  program     : 8
  • 0x01: Shut down a part
  part        : 4
  • 0x02: Start of song

This command is ignored by ScummVM 0.9.

  • 0x10: Adlib instrument definition (Part)
  part        : 4
  hw type     : 7
  adlib data  : 60*8
  • 0x11: Adlib instrument definition (Global)
  unknown     : 7
  hw type     : 7
  intrument   : 7
  adlib data  : 60*8
  • 0x21: Parameter adjust
  part        : 4
  hw type     : 7
  param       : 16be
  value       : 16be
  • 0x30: Hook - jump
  unknown     : 7
  cmd         : 8
  track       : 16be
  beat        : 16be
  tick        : 16be
  • 0x31: Hook - global transpose
  unknown     : 7
  cmd         : 8
  relative    : 8
  value       : s8
  • 0x32: Hook - part on/off
  chan        : 4
  cmd         : 8
  value       : 8
  • 0x33: Hook - set volume
  chan        : 4
  cmd         : 8
  value       : 8
  • 0x34: Hook - set program
  chan        : 4
  cmd         : 8
  value       : 8
  • 0x35: Hook - set transpose
  chan        : 4
  cmd         : 8
  relative    : 8
  value       : s8
  • 0x40: Marker
  unknown     : 7
  marker      : 7*n
  • 0x50: Set loop
  unknown     : 7
  count       : 16be
  tobeat      : 16be
  totick      : 16be
  frombeat    : 16be
  fromtick    : 16be
  • 0x51: Clear loop

No arguments (or at least unused by ScummVM).

  • 0x60: Set instrument
  chan        : 4
  instrument  : 16be

Adlib instrument

See some Adlib/Soundblaster documentation: http://www.shipbrook.com/jeff/sb.html

  operators             : 8*5*2
    characteristic      : 8 (port 0x20)
    scalingOutputLevel  : 8 (port 0x40)
    attackDecay         : 8 (port 0x60)
    sustainRelease      : 8 (port 0x80)
    waveformSelect      : 8 (port 0xE0)
  feedback              : 8 (port 0xC0)
  flags_a               : 8
  extra_a               : 8*8
  flags_b               : 8
  extra_b               : 8*8
  duration              : 8