Sounds and Images - KVonGit/zil-stuff GitHub Wiki

To compile a game with sound, we must include SOUND as a ZIP-OPTION like so:

<ZIP-OPTIONS SOUND>

The most basic way to play a sound:

<SOUND ,SOUND-ID>

What is the sound ID, you ask? Well... That depends on what decade you are in!

We will begin with the way things work with Frotz for DOS, but I'll wrap this part in <details></details> since it is not at all what we need for modern in interpreters.

Sound for Frotz on DOS

CLICK HERE FOR INFO CONCERNING OLD TECHNOLOGY Let's say our game is titled frobby.z5. Our game folder should be like this:
frobby
- frobby.z5
- sound
  - frobby03.snd

https://www.ifarchive.org/if-archive/infocom/info/sound_format.txt

In all formats, 16bit values are stored in the order MSB (most
significant byte) first - LSB (least significant byte) last.


2) Today's sound format (used by the **_sound.zip packages)
-----------------------------------------------------------

This simple format is actually a somewhat restricted version of
Infocom's Macintosh format. The name of a sound file is derived
from the name of its story file: First the story file name is
truncated to six letters, then two decimal digits for the sound
effect number are added. Finally, the extension snd is appended
to this string. (For example, "sherlo03.snd" is sound effect #3
of the story file "sherlock.dat".)

A sound file consists of a small header followed by sample data:

	+------+------+--------------------------+
	| pos  | size | contents                 |
	+======+======+==========================+
	|   0  |   2  | length of following data | prefix
	+------+------+--------------------------+
	|   2  |   1  | repeats to play          | header
	|   3  |   1  | base note                |
	|   4  |   2  | sample frequency         |
	|   6  |   2  | *** unused ***           |
	|   8  |   2  | sample data length       |
	+------+------+--------------------------+
	|  10  |   ?  | 8-bit unsigned mono data | sample data
	+------+------+--------------------------+

The "length of following data" is simply the file size - 2. The
"repeats to play" is either 0 for infinite repetition or 1. (In
Z-code 5, this value is ignored altogether.) "base note" is not
really important. For instance, if the sample data is the sound
of a instrument playing the note c then "base note" should hold
an appropriate MIDI value (Infocom usually chose $32 or $3c for
their own sound files). The "sample frequency" and "sample data
length" hold all vital information for playing the sound.

[...]

5) Sound supporting programs
----------------------------

Sound conversion utilities:

    "SoundConv" for Archimedes (Infocom module available at ftp.gmd.de)
    "SOX" for Amiga, MS-DOS, Unix etc. (beta available at ftp.gmd.de)

Both of those utilities are on ifarchive. I haven't found the Archimedes software anywhere, and I can't figure out how to build this old modified version of SoX:

Sox.tar.gz 19-Jan-1996

View contents

Beta version of the SOX sound kit (SOund eXchange by Lance Norskog et al.) with support for Infocom format sound files by Brian Kelley. C source code for DOS, Unix, OS/2, OS9, Amiga, and Windows NT.


I got Google Gemini to help create a C program to convert to a .SND file that works in Frotz 2.4.0 on DOS.

https://github.com/KVonGit/zil-stuff/wiki/mkznd

I use Audacity to export my sounds to:

  • RAW
  • Mono
  • 16,000 Hz
  • 8-bit Unsigned
image

Then mkznd s03.raw will output s03.snd. Your filename should match the first 6 characters of your game name + the sound ID you will use in your game's code to play the sound. So, if your game file's name is 'gamename.z5', your sound with 3 for the ID should be named 'gamena03.snd'.

All sound files need to be in a sub-folder named "sound" for Frotz 2.4.0 to find them, like this:

gamename/
- sound/
  - gamena03.snd
- gamename.z5

Sound for Windows Frotz (and Parchment conversions)

For modern interpreters, we must cast the blorb spell on our resource files.


Method 1 - Using the online blorbtool https://eblong.com/zarf/blorb/blorbtool/run.html

Bare minimum to make things work:

  • Create new blorb
    • Add chunk
      • upload our OGG as OGGV: Audio - Ogg
        • edit that chunk's Usage, setting it to Snd -> SND_ID_USED_IN_ZIL (click save to save the changes!)
    • export the blorb
    • rename the downloaded file from "blorb.blb" to "game_name.blb" (using the actual game file name in place of game_name, mine ends up being frobby.blb)

With the game file frobby.z5 in the same folder as frobby.blb, just open frobby.z5 in Windows Frotz, and it will all work.

Note

We can also upload our story file here. With the ogg chunk already added, I add another chunk. I upload my .z5 file, and it is automatically recognized as the z-machine story file. I edit that new chunk's Usage to Executable 0 and save the changes. Then, export the blorb and rename it frobby.zblorb. This includes the game and the sound, so need for any other files. We can also add image chunks and do this with .z6 games, by the way.


Method 2 - Using inblorb

If you have Inform 7 installed, you already have inblorb.

First, we need to create a blurb file with our text editor. I'll use my files' names for 'storyfile' and 'sound 3':

copyright "KV 2025"
release "1"
storyfile "frobby.z5" include
sound 3 "audiotest03.ogg"

Now use inblorb to cast the spell!

& 'C:\Program Files\Inform\Compilers\inblorb.exe' .\frobby.blurb .\frobby.zblorb

Now, we can run our .zblorb in Windows Frotz.


Parchment Site Generator

https://iplayif.com/api/sitegen

We can upload our .zblorb here to convert our game to an HTML file, which is a standalone website version of our game. The sounds will be intact.

Note

If you use <SOUND 1> or <SOUND 2> in your code, the Parchment version will not trigger the operating system's beep. Nothing will happen. It will play our sounds that we package in the blorb, though.


IMAGES

Zilf will only allow images with the version set to YZIP, and we must include DISPLAY in the ZIP-OPTIONS.

<VERSION YZIP>
<ZIP-OPTIONS DISPLAY>

Note

To allow sound and graphics: <ZIP-OPTIONS DISPLAY SOUND>

To display a picture: <DISPLAY .IMAGE-ID .X .Y>

So, to display my image with an ID of 2 at the top left (1,1): <DISPLAY 2 1 1>

That will cover any existing text that may fall under that image, depending on the image's dimensions.

I am new at this, but I found that CURGET will put the X,Y coordinates of the cursor's current position into a table.

First we must create global for the table: <GLOBAL CURSOR-LOC-TBL <TABLE 0 0>>

Then, we call CURGET from our routines to put the values in our table: <CURGET .TABLE1>

Now, we can use the table to set the values: <DISPLAY 2 <GET ,CURSOR-LOC-TBL 0> <GET ,CURSOR-LOC-TBL 1>>

That would display my image with an ID of 2 in my blorb at the current cursor position.


Note

The only interpreter that has successfully displayed my images is Windows Frotz. I have dfrotz and the Curses version of Frotz to run from the console. Both seem to successfully load the data, but they cannot display the PNG images (of course); Gargoyle does not attempt to display the images; and after converting to Parchment, attempting to run a command that uses DISPLAY crashes the game.


To add pictures to a blorb, it's the same process as adding sounds, except for the type and usage (of course).

Method 1 - Using inblorb

This time, my game name is imagetest**. Here is my imagetest.blurb (again, like sounds, for blorb purposes, the actual filenames need not match any special patterns -- just use your files' names in the blurb):

picture 2 "images/imaget02.png"
picture 3 "images/imaget03.png"
picture 4 "images/imaget04.png"
picture 5 "images/imaget05.png"
picture 6 "images/imaget06.png"
picture 7 "images/imaget07.png"
sound 3 "sound/audiotest03.ogg"

Now use inblorb to cast the spell!

& 'C:\Program Files\Inform\Compilers\inblorb.exe' .\imagetest.blurb .\imagetest.blb

Now, we must have imagetest.z6 and imagetest.blb in the same folder together, and opening the .z6 file with Windows Frotz should work correctly.


Method 2 - Using the online blorbtool

Same process as sound, except:

  • When adding a chunk, I upload a PNG, and it is recognized as PNG: Image - PNG
    • after adding the chunk, edit the Usage, which is already set to Picture... we only need to set the proper ID value.
      • best practice is to use ID 1 for the cover image; so I always start from 2 when adding an ID to all my images
        • be sure to save the changes to the Usage!

After adding all the chunks, export the blorb and rename the same as described when adding sounds.

And again: this will only work successfully for me in Windows Frotz.


The ZIL (and the Story Files)

The source (and game) files are in this repo.

Audio example (XZIP): https://github.com/KVonGit/zil-stuff/tree/main/projects/audio-test

Audio and Pictures example (YZIP) (very rough): https://github.com/KVonGit/zil-stuff/tree/main/projects/imagetest


Example Game with sound and pictures

<VERSION YZIP>
<ZIP-OPTIONS DISPLAY SOUND>
<CONSTANT RELEASEID 1>
<CONSTANT GAME-BANNER "IMAGETEST">

<INSERT-FILE "parser">

<ROUTINE GO ()
    <CRLF>
    <CRLF>
    <SETG MODE ,VERBOSE>
    <SETG HERE ,TESTING-AREA>
    <MOVE ,PLAYER ,HERE>
    <INIT-STATUS-LINE>
    <DISPLAY 2 1 1>
    <V-VERSION>
    <CRLF>
    
    <V-LOOK>
    <MAIN-LOOP>>

<ROOM TESTING-AREA
  (IN ROOMS)
  (DESC "Testing Area")
  (LDESC "You are in a nondescript testing area.")
  (FLAGS LIGHTBIT)
>

<OBJECT FROB
  (IN TESTING-AREA)
  (DESC "frob")
  (IMG 5)
  (SYNONYM FROB)
  (ACTION DISPLAY-ME-R)
>

<OBJECT BAR
  (IN TESTING-AREA)
  (DESC "bar")
  (IMG 4)
  (SYNONYM BAR)
  (ACTION DISPLAY-ME-R)
>

<OBJECT GREEN-BUTTON
  (IN TESTING-AREA)
  (DESC "green button")
  (LOOK "Just push it.")
  (SYNONYM button)
  (ADJECTIVE green)
  (FLAGS DEVICEBIT)
  (ACTION GREEN-BUTTON-F)
>

<ROUTINE GREEN-BUTTON-F ()
  <COND
    (<VERB? PUSH>
      <TELL "You (should) hear a bleep. (1)" CR>
      <SOUND 1>
    )
  >
>

<OBJECT BLUE-BUTTON
  (IN TESTING-AREA)
  (DESC "blue button")
  (LOOK "Just push it.")
  (SYNONYM button)
  (ADJECTIVE blue)
  (FLAGS DEVICEBIT)
  (ACTION BLUE-BUTTON-F)
>

<ROUTINE BLUE-BUTTON-F ()
  <COND
    (<VERB? PUSH>
      <TELL "You (should) hear a bloop. (2)" CR>
      <SOUND 2 2 8>
    )
  >
>

<OBJECT YELLOW-BUTTON
  (IN TESTING-AREA)
  (DESC "yellow button")
  (LOOK "Just push it.")
  (SYNONYM BUTTON)
  (ADJECTIVE YELLOW)
  (FLAGS DEVICEBIT)
  (ACTION YELLOW-BUTTON-R)
>

<ROUTINE YELLOW-BUTTON-R ()
  <COND
    (<VERB? PUSH>
      <TELL "You (should) hear a DUMMY talking. (3)" CR>
      <SOUND 3 2 8>
    )
  >
>

<OBJECT RED-BUTTON
  (IN TESTING-AREA)
  (DESC "red button")
  (LOOK "Push this button to stop any sound that is currently playing.")
  (SYNONYM button)
  (ADJECTIVE red)
  (FLAGS DEVICEBIT)
  (ACTION RED-BUTTON-F)
>

<ROUTINE RED-BUTTON-F ()
  <COND
    (<VERB? PUSH>
      <TELL "All sounds should now stop, if any are playing. (0 3)" CR>
      <SOUND 0 3>
    )
  >
>


<ROUTINE DISPLAY-ME-R ()
  <COND
    (<VERB? EXAMINE>
      <DISPLAY-IMAGE-IN-LINE>
    )
  >
>

<GLOBAL CURSOR-LOC-TBL <TABLE 0 0>>

<ROUTINE DISPLAY-IMAGE-IN-LINE ("OPT" (OBJ ,PRSO) "AUX" TABLE1 OBJ-IMG)
  <CURGET .TABLE1>
  <SET OBJ-IMG <GETP .OBJ ,P?IMG>>
  ;"TODO - ADD CHECK TO BE SURE .OBJ-IMG IS NOW DEFINED!"
  <DISPLAY .OBJ-IMG <GET ,CURSOR-LOC-TBL 0> <GET ,CURSOR-LOC-TBL 1>>
  <CRLF>
  <CRLF>
>
⚠️ **GitHub.com Fallback** ⚠️