GithubHelp home page GithubHelp logo

chapelr / harlowe-audio Goto Github PK

View Code? Open in Web Editor NEW
26.0 2.0 5.0 14.85 MB

An audio library for use with the Twine 2 story format Harlowe (v2.x or higher).

Home Page: https://twinelab.net/harlowe-audio/

License: The Unlicense

JavaScript 91.19% CSS 8.81%
twine2 twine audio harlowe

harlowe-audio's Introduction

Warning

Testing with v3.3.0 of Harlowe is ongoing. Please report any errors or problems here.

What is HAL?

Try out the demo.

HAL is an audio library for Harlowe (v2.1.0 or higher) designed to give the format feature parity (or close to it) with SugarCube's audio subsystem. This library was designed from the ground up specifically for use with Harlowe, and is intended to be as easy to use as possible for novice programmers without compromising functionality.

Features

  • All the core features you'd expect from such a library: playing across passages, fading, looping, individual track volume levels, etc.
  • Support for audio playlists.
  • Support for "audio groups," which let authors control track settings on groups of related tracks all at once.
  • Includes an optional, user-configurable sidebar with built-in audio controls; specifically a master volume control and a master mute button.
  • Supports preloading of audio, with an optional loading screen.
  • Configurable and extensible for users who need it, with sane defaults and a bevy of built-in features for users who don't want to mess with any of that.

Getting the Library

You can download any version of HAL from here. If you're just getting started, it's highly recommended that you grab the latest version. Once you've downloaded the library, you'll need to read the guide or the documentation to learn how to use it.

There are two main version of HAL. The latest version 2 release is recommended for most users. If you're already using version 1 in your project, you don't have to update if you don't want to and can instead grab the latest version 1 release. The version 1 docs are here.

See below for a guide on the basics of using HAL.

Quick Links


Guide

This is a quick and dirty guide to getting HAL working. You're here for audio, and this guide aims to please. This library has a lot of other nice features you may need to come to grips with later, but for now, we'll focus on the bare minimum you'll need to know to take your story from a boring, soundless husk to grooving like it's 1999.

Note

This guide is intended to get users up and running with HAL quickly and without too much fuss. It covers v2.0.0 and higher, for v1, check out its docs. For detailed reference documentation for v2, click here.

Installing HAL in Twine 2

To install HAL, all you need is the code, which you can get on the releases page of the repo. You should choose the version with the highest version number. Download the harlowe-audio.zip file and unzip it. There should be three files, harlowe-audio.min.js, harlowe-audio.min.css, and LICENSE. Open the harlowe-audio.min.js file in a text editor, copy all of the contents, and paste it into your story JavaScript area in Twine 2. To find the story JavaScript area, click the up arrow next to your story's name in the editor (bottom left-hand side), then click the appropriate menu option.

The story JavaScript menu option in the Twine 2 editor.

You'll then do the same thing with the harlowe-audio.min.css file, pasting it into the story Stylesheet area instead.

The story Stylesheet menu option in the Twine 2 editor.

Tip

You should open these files in a text editor, not a word processor. Any text editor you have, like notepad, will work fine for this. Opening the file in a word processor may cause the code to stop working, as they sometimes convert certain characters into other characters on loading files—like turning normal quotes ("...") into curly quotes (“...”)—that can mess up programming code.

Once all the code is in place, try playing your story. If you see a gray sidebar on the left with a white arrow at the top, and you don't encounter any errors popping up, you've installed it right!

If you have a sidebar like this and no errors, HAL has been installed correctly.

Defining Tracks

There are a few ways to define tracks, but the easiest (and recommended) way is with a special passage called hal.tracks.

Tip

What is a Special Passage? A special passage is a concept from Twine 1 and SugarCube where certain passages with special names have meaning to the story format. Harlowe doesn't use special passages (though it does have special tags). All you need to know to create a special passage is what name to give it. So to make the special passage, create a new passage in your story and give it the name hal.tracks.

An example of the tracks special passage.

In this special passage you'll define each track on its own line. Tracks require a name and a list of URLs that point to audio files (that means they end with an audio extension, like .mp3 or .ogg). You can give a track a number of source URLs; if you do, they should be the same track just in different file formats. If you only want to use one file format, .mp3 is the safest bet. If you have the capability to create duplicates of the track in different formats, including both .mp3 and .ogg versions is recommended, as that combination will give you the maximum possible browser support.

To define a track, list the track name first, then a colon, and finally one or more source URLs. If you include multiple source URLs, the list should be comma-separated (do not include trailing commas). You do not need to quote anything, not the track names or the source URLs.

Track names should only include letters (upper or lower case), numbers, dashes (-), underscores (_), and dollar signs ($). Other characters may work but are not officially supported. That's code for "don't use them even when they seem like they're working."

An example of a hal.tracks special passage that defines two tracks—a beeping sound called beep and a song called que-pena—might look like this:

beep: ./audio/beep.mp3, ./audio/beep.ogg
que-pena: ./audio/que-pena.mp3, ./audio/que-pena.ogg

Most projects will probably want to use relative URLs as shown above, but absolute URLs are also supported. We'll get more into the weeds with these concepts in some examples later.

Playing Tracks

On a basic level, all you need to do to play a track is have this code in a passage (track: 'beep', 'play'). However, reality often resists simplicity.

This is the (track:) macro, and you give it the name of a track you've defined and a command to perform. Some commands accept additional arguments, which you can just pass to the macro after the command name. For example, to set a track to loop, you'd write (track: 'que-pena', 'loop', true). This is because the loop command accepts an argument, which should be boolean true or false; true to set the track to loop, false to stop it from looping.

The lion's share of commands don't require any arguments, and very few commands require more than one, but when they do, they have to be given to the macro in the correct order, so you will need to check the docs for those.

If you just want a looping background track and that's it, define the track in the hal.tracks special passage, then place the following code in a startup-tagged passage or in your first passage:

{
(track: 'track-name', 'loop', true)
(track: 'track-name', 'playwhenpossible')
}

Note

When you write one of HAL's custom macros in the Twine 2 passage editor, it will show up colored in red like macros that don't exist. It is not possible for a library like this to edit Harlowe's syntax highlighting feature, so this is unfortunately impossible to fix. Just know that it's expected behavior and doesn't mean you did anything wrong.

Examples

Now that you've got HAL installed and you know how to define a few tracks and play them, we'll cover a bunch of common use-cases here. To see more complex examples and use-cases, and learn more about what else you can do, look at the reference documentation.

Defining Tracks with Absolute URLs

An absolute URL is a type of URL that basically tells a browser exactly where to find a resource, whereas a relative URL tells a browser where to find the resource relative to the file it's currently using. This might seem a bit confusing, but basically an absolute URL starts with http:// or https:// (prefer the latter whenever possible) and points to a file you're linking to somewhere on the web.

Here's our hal.tracks example from earlier, but with absolute links.

beep: https://example.com/audio/beep.mp3, https://example.com/audio/beep.ogg
que-pena: https://example.com/audio/que-pena.mp3, https://example.com/audio/que-pena.ogg

You can also use absolute links to point to a specific place in your computer's file system using the file:/// protocol instead of http:// or https://. Note that even on Windows systems, use forward slashes in URLs.

beep: file:///C:/twine/audio/beep.mp3, file:///C:/twine/audio/beep.ogg
que-pena: file:///C:/twine/audio/que-pena.mp3, file:///C:/twine/audio/que-pena.ogg

There are about a thousand reasons you don't want to use absolute URLs, even though they are convenient (more on that in the next example). Here's a few of those reasons:

  • If the file is on the file system, users who download your game are going to have to go and place those files in exactly the same places on their systems. E.g., in the example above, a user would have to take your audio folder and literally manually place it in C: in a folder called twine or the audio just won't work.
  • If the file is hosted on the web and served via http:// or https://, your game will require a web connection for audio, even when it's being played offline.
  • Whatever hosting service you use probably either serves an audio player rather than a file, or even if it does point to a file, it's probably against the Terms of Service of that website to hot-link to it. (Hot-linking is using someone else's website to host files for your website, and it's widely frowned upon.)
  • Relative URLs work basically everywhere, except, ironically, the two places arguably most important to Twine authors, in the Twine 2 application and on philome.la, a free Twine game hosting service.

In the big scheme of things, unless you plan to upload to philome.la, I recommend relative URLs, warts and all.

Defining Tracks with Relative URLs

In our original example for defining tracks, we used relative links. Let's look at that again.

beep: ./audio/beep.mp3, ./audio/beep.ogg
que-pena: ./audio/que-pena.mp3, ./audio/que-pena.ogg

Translation: ./ means to look in the current folder the current HTML file is in. So the file ./audio/beep.mp3 means that we look in our current folder for a folder named audio and look in that folder for our beep.mp3 file. In other words, the folder containing our game looks like this:

Our folder containing our Twine project.

Then, the inside of that audio folder looks like this:

Inside the audio folder.

When we want to share our game with friends, all we have to do is zip this folder up and email it. Or rename the game's HTML file to index.html and drop it on itch.io. Or drop the whole folder onto your website (depending on how its made and where its hosted). Or send it through web2executable to make it into a .exe file. In other words, its ready for anything. Except, as mentioned in the previous example, philome.la and, more distressingly, the Twine 2 app.

Twine 2's test and play modes run your story HTML file in memory, not from the file system. This means that it can't be relative to other files, it can only reference absolute URLs. You need to publish the game to file to be able to have a playable version with working audio.

There's two general options here: (1) use absolute URLs during development and then switch to relative URLs when you're ready to publish your game, or (2) just publish to file when you need to test the audio. Realistically, you don't have to have audio for every test play of your game during development.

The choice is yours, but I strongly recommend shipping your game with relative links unless you're targeting philome.la as your primary release platform.

Autoplay (Or, Why Won't My Audio Work on the First Passage?)

If you dropped (track: 'que-pena', 'play') in your story's first passage, there is a pretty high chance that it didn't work. Most modern browsers do not allow audio to autoplay, which means that the audio starts before the user has interacted with the page. Once the user interacts with the page, clicking on a link or something, then you can play as much audio as you want.

There are three ways to get around this limitation.

1. Use the playwhenpossible command.

The code (track: 'que-pena', 'playwhenpossible') will do two things. First and foremost, it'll attempt to play the track. If it detects that it cannot play the track, it will wait for the next valid user interaction, which should unlock autoplay, and then try to play the track again.

2. Create a splash screen.

Your game's title, credits, logo, whatever. Having a passage the user has to click through in order to get to the "real" first passage will unlock autoplay for the rest of the game, and the play command should work on every passage after that first one.

3. Tie the first track to a link.

Similar to the above, tying the play command to a link should work every time.

(link-repeat: 'Start the game.')[(track: 'que-pena', 'play')(goto: 'real first passage')]

Stopping a Sound Before Playing Another

If you need to change tracks, that is, stop one and start another, you can use the stop command.

(track: 'theme', 'stop')
(track: 'que-pena', 'play')

This, of course, assumes you know which track is playing. If you don't you can instead run the stop command on the audio group playing, which will stop all currently playing tracks.

(group: 'playing', 'stop')
(track: 'que-pena', 'play')

Another way to stop all playing tracks is via the master audio command stopall.

(masteraudio: 'stopall')
(track: 'que-pena', 'play')

Checking If a Sound Is Already Playing

You can test to see if a track is playing by combining an (if:) or (unless:) macro with the (track:) macro command isplaying:

(if: (track: 'que-pena', 'isplaying'))[
    The track is playing!
]

You may want to use this structure to check before playing a track if there's a chance the track could already be playing. For example, if there's a few different ways a user could get to a certain passage that starts playback of a track, you'd want to make sure it isn't already playing before running the play command.

(unless: (track: 'que-pena', 'isplaying'))[
    (track: 'que-pena', 'loop', true)
    (track: 'que-pena', 'play')
]

In fact, most times where music switches in your story from one background track to another, you'll probably want something that looks like this to cover all your bases:

(unless: (track: 'que-pena', 'isplaying'))[
    (group: 'playing', 'stop')
    (track: 'que-pena', 'loop', true)
    (track: 'que-pena', 'play')
]

Playing Sounds with Links

You can wrap the (track:) macro to start playback of a track inside a (link:) macro (or one of its siblings).

{
(link-repeat: 'Honk the horn.')[
    (track: 'beep', 'play')
]
}

This Is Only the Beginning

HAL has many other features, including master audio controls, playlists, and audio groups, and a variety of commands for all of it. You can also change the library's configuration settings, use JavaScript event handlers to plug into various audio events and even edit the sidebar to display a menu.

To learn more, check out the reference documentation. It's a bit drier and more technical than this guide, but it's worth reading if you have grander designs than what's been covered here.

harlowe-audio's People

Contributors

chapelr avatar dependabot[bot] avatar webbedspace avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

harlowe-audio's Issues

Javascript Code Error

When I paste the js file into Twine's JS Editor
Screenshot (107)
Screenshot (108)
Screenshot (109)
I get this error and most of the code is greyed out. I'm not sure what's wrong as I copied and pasted exact code

Improve performance.

The special passage parser could probably be rewritten to be faster. Collection data could also be simplified and DOM lookups reduced or eliminated.

(Undefined Property Issues) Report more informative error message when an undefined track is accessed.

Hi! I'm using the Twine 2 app and have the latest version installed. I installed the latest version of HAL and it seems to be installed correctly (as a gray sidebar where you can adjust the volume and mute is available once playing the project). I've defined a track in a separate passage, following the exact naming conventions of the guide, but once I try to play it (for example with this code, obviously with the actual names of said tracks):
{
(track: 'track-name', 'loop', true)
(track: 'track-name', 'playwhenpossible')
}

or code such as: (track: 'beep', 'play')

I get an error message once I try to run it, saying: Error in the (track:) macro: Cannot read property 'loop' of undefined.

Or 'playwhenpossible' undefined, and so on. Basically the commands do not seem to work properly?

I've tried this code in both the very first passage as well as later passages, with the same result. I'm not a programming whiz, but from what I can gather this basically means that the function hasn't been defined properly, somehow? I'm really at a loss, because it seems like implementing sound smoothly is so close yet so far away, hahah.

Worth adding is that I've also made sure to use a proper text editor so the code shouldn't be corrupt somehow?

Thank you beforehand!

Todo

Track.is() is broken.

Clean up preloader.

setup.js should call Track.renew().

Docs.

Proofread.

Write up a separate, complete JavaScript API doc.

Explore issues with blur and focus.

User reports issue where a track is played via playWhenPossible and looped, then a few passages later, that track is stopped and a second track is played. If the user then leaves and re-enters the tab, the first track begins playing again.

Problem with disabling sidebar.

In Story Javascript page:
controls : { show : false,

instead of true

Returns:

There is a problem with this story's script (#1):
Cannot read property 'UpdateVolume' of undefined

Everything seems to run as normal, and sidebar is in fact removed. Just curious as to why this appears and what can be done about it.

JavaScript Code Error when placed into Twine.

Hello. I was looking to use this on one of my twine projects, but I think there are some errors with how the code is formatted since some of the code doesn't work and I get script errors.
image
This is the error I keep receiving. Then I look into the code and notice that all code after this point stops working.
image
Then if I try to fix it, I get another code stopping here.
image
I have little to no knowledge in JavaScript so I'm unsure how to fix these problems. Any time I try to fix these errors I just create new errors.

Problem with story's first script

Hello, I emailed you about a problem that has just started happening for my story.

I get this message when opening the html file in Safari:

"There is a problem with this story's 1st script:

TypeError: null is not an object (evaluating 't[1]')
s

map

eval code
eval@[native code]"

Opening it in other browsers gives slightly different messages. The story works fine but the music doesn't play. I've tried https://twinelab.net/harlowe-audio/demo/ and that works fine for me on both Firefox and Safari.

HAL was working fine for ages and this has only just come up.

It won't allow me to upload an html here so I will email that to you. If you need any other info just let me know.

Thanks for your help!

Error when not showing controls

If I set controls.show to false, then Twine reports an error when I try to launch the game:

There is a problem with this story's script (#1):

Cannot read property 'updateVolume' of undefined

Audio not playing on Safari

Hi, Thank you for the HAL. I want to use it to play a background sound across a series of Twine/Harlowe pages without the sound restarting on each new page. Your library works fine to do this with Chrome, Opera and Firefox, I cannot play any sound with your system using Safari.

Mac OS 10.15.7
Safari 14.0

I tested it by writing my own page and using your demo (https://twinelab.net/harlowe-audio/demo/) where neither the beeps nor the background music will play.

I am able to play sound with this same Safari browser from other websites such as https://www.zombo.com (which I believe is using the HTML5 tags to play the music - but of course this will not play the sound across different pages).

Is this a known issue? Or something maybe specific to my system? Is there any workaround?

Thanks for your time & help!

update: I tested with Safari on iOS and that plays the sound just fine.

Having an issue with the (live:) macro

Hi there. I tried stopping one track while playing another using the following method:
(live: 25s)[(stop:)(track: 'typewriter', 'stop')(track: 'paperout', 'play')]
It did stop the previous track and play the new one. However it also caused the page to kind of flicker, like it was being reloaded.
It didn't happen with Harlowe 3.2 so I was a bit confused.
Many thanks.

Having issue with (track:) macro

The track macro isn't working I'm using Harlowe 3.3.3

This is the message I’m getting
This is a call to a nonexistent or misspelled macro. This will cause an error.

Chain one track after another

I'm trying to do something that seems like it should be simple, but I don't see any documented way to do it. At one point in my game (call it "point A"), I want it to start playing a track. Then at a later point ("point B"), I want to start playing another track. But it's possible the first track won't yet have finished. In that case, I don't want to interrupt it. It should finish playing the first track, then start the second track when it reaches the end. But if the first track ends before point B, the second track should not start until the player reaches point B.

Is this possible to do?

There is no sound after the second track.

Hello.
I am using Harlowe3.3.5 with Twine2.6.2
I installed the Harlowe audio library, put some music on using macros, and uploaded the files to google drive.
And when I open the generated site via drv.tw to play on my iPhone, there is no sound after the second song.

Looking at the chrome console, the file was read and no errors were found.

Is there any solution?

Supplement
I can't speak English, so I'm using google translate to ask.
星屑-20230501T053611Z-001.zip

Testing needed.

Make sure boolean methods work in Harlowe's (if:) and (unless:) macros.

Thoroughly test the history system.

Create a demo showcase.

Adding a track macro issue

I tried adding a track macro in my story but the call is seen mispelled or nonexistent even if I paste javascript and stylesheet codes and have no problem with left bar section in my story
Ekran görüntüsü 2021-05-31 100753

I use twine 2.3.14 with harlow latest version in the website.

README confusion

I don't know if moving to the Web Audio API is something you're working on, however, the README currently says this:

This library uses the Web Audio API

When it actually uses the HTMLMediaElement API at present.

Fix for Harlowe 3.2

Features that return data need moved to the JS API or completely cut.

I need to reinforce my ability to access Harlowe's internals. That means no more reliance on anything in-engine that I don't fetch via modules myself or make from scratch.

Other Ideas:

  • completely cut Harlowe out of the loop by parsing passage content myself, maybe specially formatted HTML comments or tags?
  • figure out a way to preload tracks without hacking the State API

Audio Que

I've looked over the HAL bible and it seems that there is no way to 'que' a track to play. There are ways around it of course, such as setting the replacement audio as a variable and then having it run as soon as the prior ends, but that causes a code littered with (live:)s and other filler macros.

A cleaner and easier option would be having an "add to que' argument that would allow quick and clean audio queuing without a ton of excess code. Not required for function, but would be a very nice addition to HAL.

Multiple music/sounds in a single passage

Hi, I have sent you also an email.
Your work on Harlowe is great. I am a game design teacher (not a programmer) and I use Twine as an introduction to "coding". I have a problem because I would use a loop music AND a series of other tracks, together in a single passage. Is it possible? In your demo it seems possible (music + beep sound), but I do not understand why in my file it doesn't work. In the mail I have attached the file.
Thanks in advance.

Harlowe 3 refreshes and loads.

Refreshing and loading in Harlowe 3 now works a bit differently and may skip startup tags, which could unload or reset certain library features if they aren't handled fully via Story JavaScript.

I should test this thoroughly and update the documentation.

Synchronous looping

Hello.
This HAL thing is really excellent.
I'm a game composition teacher, not a coder, I'm afraid.
For the past 7 or so years, I've been using Twine 1.4.2 with a version of this that I modified. https://www.glorioustrainwrecks.com/node/5061 I basically made multiple musical files of precisely the same length loop (synchronously) at zero volume, then students could turn stems on and off with fades.
The playback (in at least Firefox and Chrome) was synchronous for ages. I had to add a preloading passage 2 years ago, or so, but the it was perfect again. Now, it's not.
I'm trying various things.
I know it's possible for browsers to loop stuff in line because of this. https://goodbyevolcanohigh.com/
The js is way over my head. https://goodbyevolcanohigh.com/main.0f5644a3.js
I haven't used Twine 2 much before, but I got Hal working. I can loop 2 musical files on one passage, but they're out of alignment.
I've tried the preloading macros, which are working, but the files are not playing synchronously.
I also successfully looped 2 files as a group, but they're not synchronous.
Students really appreciate this assignment. It's super sad I can't figure out how to fix it.
Do you have any suggestions? I'm aware it may be outside the scope of HAL, but I'd just love to get this working again for my students.
Thanks for your time!
Meg

Locally downloaded track not playing with 'play when possible'

Hi folks, I'm using Harlowe Audio Library to try and add a background track, and am having trouble getting the track to play.

What I'm noticing:
No sound when I click the link, and I'm getting these warnings in my browser console
All candidate resources failed to load. Media load paused. 1ec52ab6-712c-43f5-b590-e526df1da9cf.html
Source map error: Error: NetworkError when attempting to fetch resource.
Resource URL: file:///C:/Users/zephy/AppData/Local/Temp/1ec52ab6-712c-43f5-b590-e526df1da9cf.html
Source Map URL: es6-shim.map

How I'm using HAL:
I have a passage named hal.tracks
where I define my track this way: facingIt: "C:\Users\zephy\OneDrive\Documents\KomikuFacing it.mp3"

I am calling the track macro this way
(link:"and all we need")[(track: 'facingIt', 'playwhenpossible')(goto: 'Intro')]

Some version info:
-browser: Firefox 112.0.2 (64-bit)
-twine version: 2.6.2, used on Windows
-story version: Harlowe 3.3.5

Make empty tracks errors more informative. [Original: TypeError When I Open The Game]

Having issues using the system altogether. Used an older version of it a long time ago, but for whatever reason, the new version keeps throwing me this error when I copypaste the code and try to run the game:

There is a problem with this story's 1st script:
TypeError: Cannot read properties of undefined (reading 'split')
TypeError: Cannot read properties of undefined

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.