Creating a primitive music tracker in Inform 7

I have an idea for a game feature that may be difficult if not impossible to implement in Inform 7, but I am overambitious, so here goes.

I would like to make what would essentially be a very primitive music tracker that plays samples. Basically, I would have a sound file (in the usual ogg format) that plays a single note, say, a middle C. But it would only play that sound file for X amount of seconds. Then once X seconds are up, it would play the next note (an E or whatever) for Y seconds, etc.

The same idea could be done not just with individual notes but bars of music whose real-time length is known.

Why do this in the first place? This feature could allow the player to arrange the sequence of notes or musical phrases. It also allows for randomness and variation in background music.

Basic Real Time by Sarah Morayati seems like a good candidate for this, but it doesnā€™t output anything until the next turn. Real Time Delays by Erik Temple (which only works for older versions of Inform, I think), will halt the game for a specified time, so it wonā€™t work in the background. Could either of these be modified for this use case?

Is there some Inform 6 routine I should call instead? And I confess that Iā€™ve tried but donā€™t really understand Glulx Entry Points by Emily Short!

(Another approach could be detecting when the current sound file has finished playing, but as far as I know, neither the Multiple Sounds nor the Music extension does this. But maybe this would be an easier problem to solve? If you can detect when a sound has finished, you could implement a playlist of notes or music.)

2 Likes

Glk allows for sounds to detect when they finish. When I made the Bisquixe interpeter, I had to code in that part of GLK, and I think some offline interpreters do it.

For instance, if you go here to my game Audiovisual Test, you can see an example of this. Type J to hear some music, then M to fade out the music followed by P later to fade it in. You can hear a bell sound play once the volume finishes turning up or down. This is called a ā€˜volume notify eventā€™. Also, if you havenā€™t muted the background music channel, you can type I for inventory and it plays the bells, followed by a longer song once that stops playing.

One thing to watch out for is that the gaps between sounds can be messed up with different formats on different browsers; this isnā€™t an Inform thing, just a web thing. So you may have trouble getting songs to play without gaps.

No extension I know of implements this stuff, so you do have to use Glulx Entry Points. I did something like this (along with using the Music extension):

Instead of taking inventory:
	do cool noise;
	[play sound of bells on foreground;]
	
To do cool noise:
	(- glk_schannel_play_ext(gg_foregroundchan, ResourceIDsOfSounds-->(+ sound of bells +), 1, 1); -)

To do a cool crescendo:
	(- glk_schannel_set_volume_ext(gg_backgroundchan, 65535, 3000, 1); -)

Glulx input handling rule for a sound-notify-event:
	play sound of weird on background;

Glulx input handling rule for a volume-notify-event:
	play sound of bells on foreground;

(the ā€˜1ā€™ at the end of the glk_schannel stuff tells you to send a notify event, and then the ā€˜handling rule for a notify eventā€™ rules tell you what to do when you get one).

I know that behind the scenes 1 or 2 people or working on a new version that gets rid of Glulx entry points entirely and makes things better, so you can wait until thatā€™s finished, but there is as far as I know no time frame on when that will be done, so if you want something within the next year or two, Iā€™d focus on glulx entry points.

2 Likes

In case you want to try it with timers, hereā€™s an example I was given several years ago by David Kinder:

I didnā€™t use any special sound or music extensionā€“just Glulx Entry Points.

I also tried playing sounds using sound notifications, but I thought it sounded better with the timers.

1 Like

Thank you, @mathbrush and @bg! I will be checking these things out. I am hoping I have code soon that I can share with everyone. I guess thereā€™s no escaping Glulx Entry Points for now!

1 Like

I tried what I refer to as the playlist approach, inspired by @mathbrush. When one sound ends, another begins.

This code plays individual quarter notes and a quarter rest in a loop, but thereā€™s no reason it canā€™t play individual songs or phrases of a song instead. In fact, it would be preferable!

(As an aside, I was experimenting with some crossfading here, which doesnā€™t sound great ā€“ I probably would need to manually fade out each of my sound files instead of doing it in Inform.)

"Tracker Experiment" by Robert Patten

Lab is a room.

Include Music by Daniel Stelzer.


sound of c4-4 is the file "C4-4.ogg".

sound of d4-4 is the file "D4-4.ogg". 

sound of e4-4 is the file "E4-4.ogg". 

sound of rest-4 is the file "rest-4.ogg".


Table of Music
Ditty
sound of c4-4
sound of rest-4
sound of d4-4
sound of e4-4



Instead of taking inventory:
	choose note;


note-row-number is a number that varies. note-row-number is 1.

sound-to-be-played is a sound name that varies.


To choose note:
	let row-limit be the number of rows in Table of Music;
	if note-row-number is greater than row-limit:
		now note-row-number is 1;
	choose row note-row-number from the Table of Music;
	let sound-to-be-played be the ditty entry;
	let max-volume be 65535;
	let min-volume be 5;
	let fade-duration be 500;
	if note-row-number is odd:	
		start a crossfade with background going from max-volume to min-volume and foreground going from min-volume to max-volume over fade-duration milliseconds;		
		do cool noise in foreground;
	otherwise:
		start a crossfade with foreground going from max-volume to min-volume and background going from min-volume to max-volume over fade-duration milliseconds;
		do cool noise in background;		
	increase note-row-number by 1;	

	
To decide whether (N - a number) is odd: 
	if the remainder after dividing N by 2 is 0, no; 
	yes.


To do cool noise in foreground:
	(- glk_schannel_play_ext(gg_foregroundchan, ResourceIDsOfSounds-->(+ sound-to-be-played +), 1, 1); -)

To do cool noise in background:
	(- glk_schannel_play_ext(gg_backgroundchan, ResourceIDsOfSounds-->(+ sound-to-be-played +), 1, 1); -)


Glulx input handling rule for a sound-notify-event:
	choose note;

I donā€™t think this is a great approach for stringing individual notes together. Not only was there a noticable lag between notes, but I think there was a very slight delay sometimes on my computer (which is a fairly fast gaming laptop). I had hoped to have another sound channel accompanying the melody with harmony or drum beats, but I donā€™t think thatā€™s feasible, as the channels could easily get out of sync. Even if they didnā€™t (and I have yet to try this with a few bars of melody in one channel, and a drum beat in the same tempo in the other), the result would be choppy.

The timed approach could maybe work. It would be more flexible too, as I could have a note with a maximum duration time, but otherwise could cut it off for whatever duration I liked, which means Iā€™m not stuck at a single tempo (and can use the same sound file for whatever the length of the note is). But Iā€™m guessing it would also be plagued by slight hiccups that would get the channels out of sync with each other, and maybe there would still be choppy gaps. But itā€™s just a guess. I havenā€™t attempted this because honestly, Iā€™m still trying to wrap my head around the Inform 6 code passed on by @bg. :slight_smile:

Conclusion: The playlist approach is potentially useful for stringing pieces of actual music or sound effects together, but not individual notes. Itā€™s almost as though a programming language for text adventures was never meant to be a music tracker! Iā€™m shocked, shocked!

(But getting Inform 7 to do things it was never intended to do is half the fun.)

3 Likes

It might be worth mentioning the Damusix extension (by @eliukblau). It had a number of advanced features including MOD playing. It seems to be gone from github, but thereā€™s some archived material:

4 Likes

Thatā€™s really cool that you got this to work! I actually had wanted to make a kind of DJ-style inform ā€˜gameā€™ where you can add different melodies and beats, but I couldnā€™t figure out how to get started. It sounds like youā€™ve gotten as far as someone can with the current tools (and are looking into new stuff). Iā€™m really impressed and glad someone is figuring this out!

2 Likes

Thanks for your kind words and help on this, @mathbrush. I just wish my current results were better!

Iā€™ve had similar thoughts to yours on integrating music into Inform. I have toyed with the idea of creating a little demo game with a jukebox that can play and restructure different songs based on player actions.

In one of my WIPs, the major focus is letting the player be a co-creator with me, optionally weighing in on as much of the world as possible, from rooms to items to NPCs. Modding would be highly encouraged.

Having the player being able to decide on the music ā€” and even compose their own! ā€” would be more in the gameā€™s moddable spirit than me making the final decisions about sound.

I thought about giving the player some options, like ā€œThese rooms are linked to fast-moving, upbeat music, and these other rooms are linked to slow, solemn music,ā€ and the game would play a song from either category based on the room, but that doesnā€™t seem like enough.

Thatā€™s why I took the approach of listing sounds in tables in my coding experiment here. The eventual plan was to store these tables in external files. That way, a player who is so inclined could alter and compose their own music within the limitations of what the game allows without touching the source code. There could be separate channels (columns) for melody, harmony, and drums. It would be simple, but it would allow the player another outlet for making the game theirs.

But with what Iā€™ve seen of Inform 7ā€™s capabilities, this may not be feasible right now.

@n-n, mod files may indeed be the way to go (hey, modding is in the name!), and I appreciate you bringing that up! I donā€™t know enough to say whether that would work. (I feel like Iā€™m saying, ā€œI donā€™t know,ā€ a lot on this thread ā€¦) Iā€™m not familiar with the internal structure of the format, and I donā€™t know whether editing the files during gameplay would allow me to change a song on the fly (assuming editing a mod file like a text file would even be possible).

Another strategy: Would there be a way for a modder to not just extract a sound file from a glorb file but replace it with one the modder has made? Replacing files could be the easiest way to let the player have input on music in the game, if it can be done without much headache. (I can see replacing sounds being possible for an online version of the game, but desktop might be a different story.)

Thanks, everyone, for your patience as I think out loud. :slight_smile:

2 Likes

This is a really cool idea. Good luck. I wrote a spy novel in retirement, and created a Spotify playlist with a song for each chapter. In most cases, I then embedded the song title somewhere in a sentence in the chapter. Nothing as exciting (or as difficult) as what you are trying to do, but the ā€œsong per roomā€ made me think of itā€¦ The book is ā€œThe Quantum Contingentā€ā€¦ and I made a tongue-in-cheek IF game in the same universe.

Until the tools improve, a fun thing to do would be to simply have a command that tells you the song assigned to the room. The player could even offline create their own music and upload it to a website organized by room. Good luck with the project!

2 Likes