I didn't find a bug or RFE anywhere else regarding Loom-
Mac music, so here's where I'm going to post notes
about the custom format as I discover things.
The Loom Mac music resources consist of a header and up to
5 streams. Here is what is known so far:
RESOURCE DATA
LE 2 bytes Resource size
2 bytes Unknown
2 bytes 'so'
24 bytes Unknown
BE 2 bytes Offset to Stream 1
BE 2 bytes Offset to Stream 2
BE 2 bytes Offset to Stream 3
BE 2 bytes Offset to Stream 4
BE 2 bytes Offset to Stream 5
? bytes The streams
STREAM DATA
BE 2 bytes Unknown (always 1?)
2 bytes Unknown (always 0?)
2 bytes Number of events in stream
? bytes Stream data
Each stream event is exactly 3 bytes, therefore one can
assert that numEvents == (streamSize - 6) / 3.
A stream can contain events for multiple "channels". There
are two types of events: channel and universal (or System
Common in MIDI terms).
UNIVERSAL EVENTS
1 byte 0x7F
1 byte ?
1 byte ?
CHANNEL EVENTS
1 byte Channel number (0-?)
1 byte Note duration or delay before next event?
1 byte Note number to play (0 = rest)
(The first event in the stream, presumably, has a delay of 0,
since the delay before an event is embedded in the previous
event.)
The second byte of the event appears to be a temporal
measure because sequences of these bytes, with multiple
channels active, appear to add up to patterns of summations
(something that would not happen if the byte carried
command data). However, a few events contain second bytes
that completely depart from this pattern.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
lechimp, thanks for the resource information. Those do indeed
match up with information in the header -- 2 bytes for each
stream, corresponding apparently to which instrument that
stream is supposed to use.
Also, the channels-within-a-stream thing doesn't appear to
be correct. The streams themselves may very well be the
equivalent of simultaneous channels. If that's the case, then
what's interesting is that data from one channel seems to
show up in other channels, but there may be a flag I'm
missing that is used to mute those events so that they only
serve as timing references. I'm not sure yet.
So discard the information in my original notes, and here's the
new information:
RESOURCE DATA
LE 2 bytes Resource size
2 bytes Unknown
2 bytes 'so'
14 bytes Unknown
BE 2 bytes Instrument for Stream 1
BE 2 bytes Instrument for Stream 2
BE 2 bytes Instrument for Stream 3
BE 2 bytes Instrument for Stream 4
BE 2 bytes Instrument for Stream 5
BE 2 bytes Offset to Stream 1
BE 2 bytes Offset to Stream 2
BE 2 bytes Offset to Stream 3
BE 2 bytes Offset to Stream 4
BE 2 bytes Offset to Stream 5
? bytes The streams
STREAM DATA
BE 2 bytes Unknown (always 1?)
2 bytes Unknown (always 0?)
BE 2 bytes Number of events in stream
? bytes Stream data
Each stream event is exactly 3 bytes, therefore one can
assert that numEvents == (streamSize - 6) / 3. The
polyphony of a stream appears to be 1; in other words, only
one note at a time can be playing in each stream. The next
event is not executed until the current note (or rest) is
finished playing; therefore, note duration also serves as the
time delta between events.
FOR EACH EVENTS
BE 2 bytes Note duration
1 byte Note number to play (0 = rest/silent)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Oh, and quick speculation -- Stream 1 may be used for a
single-voice interleaved version of the music, where Stream 2-
5 represent a version of the music in up to 4-voice
polyphony, one voice per stream. I postulate thus because
the first stream of the Mac Loom theme music contains
interleaved voices, whereas the second stream seemed to
contain only the pizzicato bottom-end harp. Stream 5, in this
example, is empty, so if my speculation is correct, this
particular musical number supports 3-voice polyphony at
most. I must check out Streams 3 and 4 to see what they
contain.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am only happy to help :-)
Is there anything else short of hardcore programming or reverse
engineering I can help with?
I am looking forward to play Loom again and maybe I'll try to run it on
my old dusty LC II for which it was originally bought for. I could make
some comparison tests even...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I recently bought a used copy of Loom for the Mac, and using the information collected here I was able to get the Loom music playing. I don't know whether or not it sounds correct, but it sounds reasonable enough to me.
The Mac MI1/Loom music patch was accepted a month ago. I just forgot to close this feature request. As I said, it's possible that it's still not quite right but it sounds reasonable enough to me.
Thanks to everyone who worked to figure out the music format and handling Macintosh instruments! All I had to do was to put the final pieces together.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Logged In: YES
user_id=596642
The Loom Mac music resources consist of a header and up to
5 streams. Here is what is known so far:
RESOURCE DATA
LE 2 bytes Resource size
2 bytes Unknown
2 bytes 'so'
24 bytes Unknown
BE 2 bytes Offset to Stream 1
BE 2 bytes Offset to Stream 2
BE 2 bytes Offset to Stream 3
BE 2 bytes Offset to Stream 4
BE 2 bytes Offset to Stream 5
? bytes The streams
STREAM DATA
BE 2 bytes Unknown (always 1?)
2 bytes Unknown (always 0?)
2 bytes Number of events in stream
? bytes Stream data
Each stream event is exactly 3 bytes, therefore one can
assert that numEvents == (streamSize - 6) / 3.
A stream can contain events for multiple "channels". There
are two types of events: channel and universal (or System
Common in MIDI terms).
UNIVERSAL EVENTS
1 byte 0x7F
1 byte ?
1 byte ?
CHANNEL EVENTS
1 byte Channel number (0-?)
1 byte Note duration or delay before next event?
1 byte Note number to play (0 = rest)
(The first event in the stream, presumably, has a delay of 0,
since the delay before an event is embedded in the previous
event.)
The second byte of the event appears to be a temporal
measure because sequences of these bytes, with multiple
channels active, appear to add up to patterns of summations
(something that would not happen if the byte carried
command data). However, a few events contain second bytes
that completely depart from this pattern.
Logged In: YES
user_id=882471
I would like to help with this jamieson. I forgot... was it you or
superqult that didn't have the resources but only the game data
files?
Anyway, I'd be happy to help with information on them,
remapping them to MIDI perhaps, like you did with Monkey 1.
There are 10 samples in the Loom application :
Res. ID Name Size(bytes) 'sounds like' in GM
1000 "Dual Harp" 5082 - Pizzicato Strings (46)
10895 "harp1" 7254 - Orchestral Harp (47)
11445 "strings1" 6493 - String ensemble (49)
11548 "silent" 50 - nothing
13811 "staff1" 7944 - music box (11)
15703 "brass1" 10463 - saw wave (82)
16324 "flute1" 8458 - flute (74)
25614 "accordion1" 8394 - accordion (22)
28110 "f horn1" 8121 - french horn (61)
29042 "bassoon1" 2423 - bassoon (71)
They are all sampled at C4 (MIDI 60). The GM values are
estimated by ear from singular sounds, not from the music mix.
Hopefully the resource IDs match some of the values in the
'unknown' fields. Else, just ask me for more information...
Logged In: YES
user_id=882471
sorry 'bout the table alignment or lack of same :o)
Logged In: YES
user_id=596642
lechimp, thanks for the resource information. Those do indeed
match up with information in the header -- 2 bytes for each
stream, corresponding apparently to which instrument that
stream is supposed to use.
Also, the channels-within-a-stream thing doesn't appear to
be correct. The streams themselves may very well be the
equivalent of simultaneous channels. If that's the case, then
what's interesting is that data from one channel seems to
show up in other channels, but there may be a flag I'm
missing that is used to mute those events so that they only
serve as timing references. I'm not sure yet.
So discard the information in my original notes, and here's the
new information:
RESOURCE DATA
LE 2 bytes Resource size
2 bytes Unknown
2 bytes 'so'
14 bytes Unknown
BE 2 bytes Instrument for Stream 1
BE 2 bytes Instrument for Stream 2
BE 2 bytes Instrument for Stream 3
BE 2 bytes Instrument for Stream 4
BE 2 bytes Instrument for Stream 5
BE 2 bytes Offset to Stream 1
BE 2 bytes Offset to Stream 2
BE 2 bytes Offset to Stream 3
BE 2 bytes Offset to Stream 4
BE 2 bytes Offset to Stream 5
? bytes The streams
STREAM DATA
BE 2 bytes Unknown (always 1?)
2 bytes Unknown (always 0?)
BE 2 bytes Number of events in stream
? bytes Stream data
Each stream event is exactly 3 bytes, therefore one can
assert that numEvents == (streamSize - 6) / 3. The
polyphony of a stream appears to be 1; in other words, only
one note at a time can be playing in each stream. The next
event is not executed until the current note (or rest) is
finished playing; therefore, note duration also serves as the
time delta between events.
FOR EACH EVENTS
BE 2 bytes Note duration
1 byte Note number to play (0 = rest/silent)
Logged In: YES
user_id=596642
Oh, and quick speculation -- Stream 1 may be used for a
single-voice interleaved version of the music, where Stream 2-
5 represent a version of the music in up to 4-voice
polyphony, one voice per stream. I postulate thus because
the first stream of the Mac Loom theme music contains
interleaved voices, whereas the second stream seemed to
contain only the pizzicato bottom-end harp. Stream 5, in this
example, is empty, so if my speculation is correct, this
particular musical number supports 3-voice polyphony at
most. I must check out Streams 3 and 4 to see what they
contain.
Logged In: YES
user_id=882471
I am only happy to help :-)
Is there anything else short of hardcore programming or reverse
engineering I can help with?
I am looking forward to play Loom again and maybe I'll try to run it on
my old dusty LC II for which it was originally bought for. I could make
some comparison tests even...
I recently bought a used copy of Loom for the Mac, and using the information collected here I was able to get the Loom music playing. I don't know whether or not it sounds correct, but it sounds reasonable enough to me.
The current version can be found as a ScummVM pull request at https://github.com/scummvm/scummvm/pull/291
The Mac MI1/Loom music patch was accepted a month ago. I just forgot to close this feature request. As I said, it's possible that it's still not quite right but it sounds reasonable enough to me.
Thanks to everyone who worked to figure out the music format and handling Macintosh instruments! All I had to do was to put the final pieces together.