Sound effect demo (no extensions)

In case you’re looking for adding sound effects to your game, you may want to check out the new “noise” waveforms I had contributed a while back that are now available in the live version of MakeCode Arcade. These are usable without any extensions, the Melody feature allows choosing waveforms and setting envelopes, and this is also how the existing “play sound” options in the “Music” toolbox work.

Here are some examples:

For example, the “zapped” effect

~16 @10,0,255,1 !3200,500^1

works as follows:

  • select waveform 16 (cycle noise 16)
  • set the envelope - attack 10ms, decay 0ms, sustain volume 255, release 1ms
  • play the note - start at 3200 Hz, play for 500ms, and continuously drop the frequency down to 1 Hz at the end.

The documentation doesn’t show the new waveforms yet, but you can now use waveforms 16-18 for repeating pseudorandom patterns with length 16/32/64. Waveform 4 is a tunable noise which replaces the old “metallic” waveform that got removed a while back. The pre-existing waveform 5 is white noise, this ignores the supplied frequency.

Let me know if you want more explanations of how these work. And please share if you have cool sound effects that make use of this :slight_smile:

If you want to explore the available waveforms, you try this simple interactive tool. It uses the https://github.com/klausw3/pxt-sound-effects/ extension, but it’s also possible to play the same sounds using the string-based melody format.

One small gotcha is that you need to use new Melody(string) in JavaScript to create the melodies. The music.playMelody(string, tempo) method from the Music toolbox is intended to work with the melody editor, and it modifies the input string in ways that can break custom effects.

As the demo shows, it’s also possible to abuse the Melody syntax to play chords or multi-voice songs from a single melody string by setting a long decay on a super-short note, though this gets rather clunky to edit manually. For example,

~3 @20,0,255,1000 c4-99999 e g

plays a C chord using the “sine” waveform 3.

The sounds played this way still all count against the maximum number of supported simultaneous sounds, so this isn’t a way to get around that limit, but it may still be useful for simple cases since it can be tricky to synchronize a longer multipart melody when it’s split into parts. For comparison, here’s simple loops 4 which was my earlier attempt to do that.

Sorry about the long ramble, please let me know if you got this far :wink:

13 Likes

Oh these are great! I had thought they made it in in the last release, completely forgot they came in right afterwards. Thanks again for the great contributions!

(also editing to note / confirm that I got ‘this far’!)

2 Likes

I added a few more, including knock/footsteps/thump sounds intended as less-obtrusive effects for games:

Feel free to copy or modify any of this as you see fit, and please post your results if you find new and interesting sounds.

4 Likes

Thanks kwx, this is a great addition to arcade.
Is it possible to play a loop like the drum&bass example during a game like your boulders and gems game or is that too complex for the hardware arcade is intended for?

1 Like

I used his simple loops 3 project and modified it a little to work on the PyGamer for one game my son designed.

1 Like

Here’s a quick test - it works in the emulator, but I haven’t tried it on hardware yet. I basically just pasted simple loops 4 onto the end of the file, and combined the snare+hi-hat into a single percussion track to avoid sound effect collisions:

I think you’d need something longer and more interesting than a single bar of music in a loop, otherwise it’s likely to drive the poor players insane :-/ The 12-bar pattern is arguably still too short, and it doesn’t help that I’m kind of tone deaf and am trying to compose songs based on half-understood music theory…

Once you have a longer piece, you’d either end up with a gigantic melody string that would be a pain to edit manually, or you’d need to use multiple distinct parts that you’d then need to synchronize. While the single-string example is easy to use with a single play() command, it’s a bit inefficient since it repeatedly switches back and forth between waveforms and envelopes in a way that has a lot of redundant pieces.

Separately, you need to be careful about the overall parallel sound channels being used. You’ll want to keep some available for sound effects, and I think there are also some collision issues when starting new sounds while previous ones are still playing. A new bar of melody might end up cutting off an ongoing sound effect instead of replacing a sustain from the previous bar’s last note.

I think it would be an interesting experiment to see what’s possible. Anyone up for tackling something like Ballblazer’s algorithmic theme music?

3 Likes

Hm, on second thought that doesn’t actually reduce the simultaneous sounds since it’s still playing the same notes (I was meaning to simplify the pattern but forgot to do so), but in practice it seems to help. I think there’s some melody-level scheduling in addition to soundInstruction-level scheduling?

Also, I failed to solve level 8 when testing it just now, maybe I was overdoing the difficulty on that one…

Yep, there’s a limit of four simultaneous music.Melody playing instances in melody.ts, and a limit of five simultaneous sound instructions in melody.h.

So you should be OK with something like 2-3 melody loops for music while still playing sound effects even if the loops have occasional overlapping notes.

I’ve just tried the game on a PyGamer, and performance is OK on the first two levels, but the scheduling falls apart on the much larger level three when moving since the rock update takes too long. Note to self: try a slightly less brute-force algorithm?

1 Like

Thanks for all the information. The first two levels of Boulders and Gems music hack run smoothly on Meowbit which is a bit weaker than Pygamer, I think.
The music sounds great on the hardware buzzer.
I’ll try to add some music to my Pergamon game and report how it goes :slight_smile:

2 Likes

Oh this is amazing

1 Like

These are fantastic! I had assumed they were included in the last release, but I entirely forgot they were included shortly after. Thank you once more for your outstanding contributions, and the drum beat maker are really amazing

This is ingenious, thanks! And I have allowed myself to shamelessly copy your melody loop method to try to get Dr. Dre’s Still to play in a small demo I am trying to make.

Do I understand you correctly then, that any way to try to play a 3-note chord, either as three separate melody lines or three rapid consecutive notes with long decay, both count as 3 out of 4 or 5 maximum simultaneous for the duration of the decay?

So to achieve Dr Dre’s Still with also the melody line, which consists of 1 drum line, 2 simultaneous bass notes(2-note chord), 3 simultaneous harmony notes(3-note chord) and 1 melody line, I am forced to drop 1 note from the bass chord and one note from the harmony chord?;
1 drum line, 1 bass note, 2 harmony notes and 1 melody line maximum, either way?

Or could the whole “picture” be manipulated somehow, to sound complete?

1 Like

On a second thought, I could maybe just mix in the string melody(ta-ta-ta-ta-ta-ta-ta-taaah) as a replacement on the end of the 3rd harmony note line, since it does not occur that often.

Though it would sound a lot “thicker”/better if I could sneak them in somehow without removing that part of the 3rd harmony note line and removing 1 of the bass chord note lines…

The progress so far:

Any working suggestions for improvements are greatly appreciated!

1 Like

That’s how I understand it. The melody.h limit of 5 low-level sound instructions is a hard limit on the number of simultaneous sounds that are playable at one time. Any audible sound counts against this, including the decay of a previously played note.

Whatever method you use to play a 3-note chord counts against this 5-sound-instruction limit.

I’m guessing the higher-level limit of 4 melodies is intentionally smaller than the 5-sound-instruction limit so that there’s some room for a previous note to decay while the next note is playing.

One aspect that I found a bit hard to work with is how to smoothly switch out sounds without gaps, for example if I wanted a continuous background engine noise with adjustable pitch for a car game. It would be nice if you could send sound instructions to a specific channel, but I think that’s not directly possible.

If I’m reading the code correctly, adding a new sound instruction just makes it play simultaneously with the pre-existing ones until you hit the 5-instruction limit, and at that point the oldest gets evicted. Maybe the cleanest approach to replace a background sound would be to use music.stopPlaying() to ensure all are stopped, then re-issue the sound. However, I think it caused audible pops when I tried this, though I may be misremembering.

1 Like

Thanks again for the clarifications and insights!

I noticed, when playing back on hardware(RPi), the limit was 4, even one less simultaneous sound than in the web simulator, interpreting your playback algorithm in some strange combinatorics/modulo of which only 4 of 5 sound could play at one time, consistent with you description above.

But hey, 4 or 5 channels is pure luxury, and I guess there is still great room for improvement in MakeCode Arcade, by studying some of the magic tricks from both old and newer legends, who made music that sounded like fully seated orchestras with far less at hand! :wink: