Does anyone have tips on playing audio in JS/Elm?

I figured this would be fairly simple using ports.

In the Elm port module, I simply set up an outgoing port:

port play : String -> Cmd msg --string is the filename of the audio file

and in the JS

var app = Elm.Main.init({node: document.getElementById('elm')});
app.ports.play.subscribe(function(fn) {   
    var audio = new Audio(fn);
    audio.play();
  });

Yet the console immediately shows me an error message (in the app.ports.play line) of

Uncaught TypeError: Cannot read property 'play' of undefined.

The rest of the embedded Elm works fine, but I can’t find a way past this one.

Any tips gratefully received.

Hello, are you sure you run play function somewhere in your elm code? Looks like compiler didn’t put play function into the output bundle.

Yes, it’s all in there.

in the view function


button [onClick Play] [text "Play >"]

in the update function


Play -> (model, play (sourceFromItem model.currentItem))

It fails on the page load, not on the click of the button.

Well, check this article on contentloaded. https://thoughtbot.com/blog/bridging-elm-and-javascript-with-ports

Thanks - I’d read that and it was one of the places I borrowed some structure from.

It’s no biggie - I can do the whole thing in HTML/JS, it would just be nicer in Elm.

Hi!

Your approach looks good! (I’d just rename the fn parameter in your JS to url to make things less confusing.)

The error you’ve encountered does not seem to have anything to do with audio, though!

If the compiler does not detect any ports being used in your program at all, it won’t even define .ports on your app. So when you try to call app.ports.play.subscribe() on page load, it fails to read .play because app.ports does not exist.

Now, it sounds like you do have defined and used a port, but it’s hard to tell what’s actually going on without seeing the full picture.

Thanks. Yes, this is beyond me.

I have defined type Msg = NoOp | ChangeName | Play, but the compiled JS for the update function doesn’t seem to include the Play msg, and I have no idea how to add it in.

var $author$project$Main$update = F2(
	function (msg, model) {
		switch (msg.$) {
			case 'NoOp':
				return model;
			case 'ChangeToName':
				var s = msg.a;
				return _Utils_update(
					model,
					{
						currentItem: A2($author$project$Kontent$findItemFromTitle, s, model.kontent)
					});
			default:
				return model;
		}
	});

All a bit baffling, but I refactored some code and the compiled Play function appeared.

Why not simply use the HTML5 audio element? Works perfectly fine.

1 Like

The reason was that I’m not playing a specified file, but a user-selectable file (in Elm), the filename being sent via ports to JS.

I have it working OK now, the problem was caused by my deliberate forgetting of Javascript and its ways.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.