DEV Community

Cover image for Make the sound of Mario's coins in your browser!
kurokky(黒木シンタロー)
kurokky(黒木シンタロー)

Posted on • Updated on

Make the sound of Mario's coins in your browser!

Let's take a quick look and Click "?" on this page!

The started

I wanted to sound in my browser. I did some research and found a way to convert mp3 and m4a files to base64 and play them, but that method was not what I wanted to do. A little more investigation revealed that it can be done with "AudioContext".

Moreover, the parameter was 'triangle, 'sine,' 'square,' 'sawtooth,' which were the very sounds used in the NES.

If this happens, I'll have to do it!

What made you think of NES?

No need to talk about the sound of NES in this day and age, right? Please bear with me for a moment.
If I talk in detail about the specifications of the NES sound, there are about eight different types of sounds, because some of them have changed the ratio of square waves, but basically only four sounds can be produced.

name details
square for melodies / can play two sounds same time.
triangle for bass, sound effects
noise for drums , rhythm , sound effects
DPCM voice etc.

As mentioned above, when people see "square wave and triangle wave," people over the age of 40 definitely think it's the NES. Some NES geeks may have "Konami Sound Staff Club Kukeiha" in mind.

Technical

If you look at the source, there is nothing particularly difficult to do, so if you want to play the sound of a coin, you can do so by playing the "E" sound after the "B" sound.

It looks like this.

const AudioContext = window.AudioContext || window.webkitAudioContext
const audioContext = new AudioContext()
const gainNode = audioContext.createGain()
gainNode.connect(audioContext.destination)
gainNode.gain.value = 0.1
const oscillator = audioContext.createOscillator()
oscillator.connect(gainNode)
oscillator.type = "square"
oscillator.frequency.setValueAtTime(987.766, audioContext.currentTime)//B
oscillator.frequency.setValueAtTime(1318.51, audioContext.currentTime + 0.08)//E
oscillator.start()
oscillator.stop(.5)
Enter fullscreen mode Exit fullscreen mode

Be careful not to specify gain.value or your ears will die...(super loud). My sense of sound was not up to par, and I couldn't make out the sound of the power-up and entering the clay pipe no matter how I tried, so I had to analyze it at about 10% speed.(I don't think it is possible for normal people.)

If you listen carefully, there are some strange things. but I tried to do a lot of things with WebAudio-PulseOscillator, but I just thought, "I'll just use the default sound." and "I'll do it with what I have!"

If you really work hard, you could probably make something serious by having it read midi and MML with the technology to make synthesizers, and it would be interesting to make an application for it in electron.

important point

I thought it would be tasteless to use only buttons, so I tried to reproduce the dots using table tags, but this is a "bonus" because of the rights issue.

Correspondence table

If you are interested in doing something similar, this might be useful.

note Hz etc
A 6.875
A# 7.283
B 7.716
C 8.175 MIDI LOW
C# 8.661
D 9.177
D# 9.722
E 10.3
F 10.913
F# 11.562
G 12.249
G# 12.978
A 13.75
A# 14.567
B 15.433
C 16.351
C# 17.323
D 18.354
D# 19.445
E 20.601
F 21.826
F# 23.124
G 24.499
G# 25.956
A 27.5 Piano Low
A# 29.135
B 30.867
C 32.703
C# 34.647
D 36.708
D# 38.89
E 41.203
F 43.653
F# 46.249
G 48.999
G# 51.913
A 55.0
A# 58.27
B 61.735
C 65.406
C# 69.295
D 73.416
D# 77.781
E 82.406
F 87.307
F# 92.498
G 97.998
G# 103.826
A 110.0
A# 116.54
B 123.47
C 130.812
C# 138.591
D 146.832
D# 155.563
E 164.813
F 174.614
F# 184.997
G 195.997
G# 207.652
A 220.0
A# 233.081
B 246.941
C 261.625
C# 277.182
D 293.664
D# 311.126
E 329.627
F 349.228
F# 369.994
G 391.995
G# 415.304
A 440.0
A# 466.163
B 493.883
C 523.251
C# 554.365
D 587.329
D# 622.253
E 659.255
F 698.456
F# 739.988
G 783.99
G# 830.609
A 880.0
A# 932.327
B 987.766
C 1046.502
C# 1108.73
D 1174.659
D# 1244.507
E 1318.51
F 1396.912
F# 1479.977
G 1567.981
G# 1661.218
A 1760.0
A# 1864.655
B 1975.533
C 2093.004
C# 2217.461
D 2349.318
D# 2489.015
E 2637.02
F 2793.825
F# 2959.955
G 3135.963
G# 3322.437
A 3520.0
A# 3729.31
B 3951.066
C 4186.009 Piano HIGH
C# 4434.922
D 4698.636
D# 4978.031
E 5274.04
F 5587.651
F# 5919.91
G 6271.926
G# 6644.875
A 7040.0
A# 7458.62
B 7902.132
C 8372.018
C# 8869.844
D 9397.272
D# 9956.063
E 10548.081
F 11175.303
F# 11839.821
G 12543.853 MIDI HIGH
G# 13289.75
A 14080.0
A# 14917.24
B 15804.265
C 16744.036
C# 17739.688
D 18794.545
D# 19912.126 HUMAN HIGH
E 21096.163
F 22350.606
F# 23679.643
G 25087.707
G# 26579.5

Top comments (9)

Collapse
 
lionelrowe profile image
lionel-rowe

It's an octave higher than the original, at least based on this:

youtube.com/watch?v=qfx6yf8pux4

You can tune down by an octave by halving the frequencies:

- oscillator.frequency.setValueAtTime(1975.533, audioContext.currentTime)//B
- oscillator.frequency.setValueAtTime(2637.02, audioContext.currentTime + 0.08)//E
+ oscillator.frequency.setValueAtTime(1975.533 / 2, audioContext.currentTime)//B
+ oscillator.frequency.setValueAtTime(2637.02 / 2, audioContext.currentTime + 0.08)//E
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kurokky profile image
kurokky(黒木シンタロー)

Thank you. Changed.

Collapse
 
lionelrowe profile image
lionel-rowe • Edited

No problem!

The halving/doubling to go down/up an octave is pretty fun. You could do something like this, mapping an octave to its relevant power of 2:

const coin = (octave) => {
    const multiplier = 2 ** octave

    const audioContext = new (window.AudioContext ?? window.webkitAudioContext)()

    const gainNode = audioContext.createGain()

    gainNode.connect(audioContext.destination)
    gainNode.gain.value = 0.1

    const oscillator = audioContext.createOscillator()

    oscillator.connect(gainNode)
    oscillator.type = "square"

    oscillator.frequency.setValueAtTime(987.766 * multiplier, audioContext.currentTime)
    oscillator.frequency.setValueAtTime(1318.51 * multiplier, audioContext.currentTime + 0.08)

    oscillator.start()
    oscillator.stop(.5)
}

;(async () => {
    for (let i = -7; i < 4; ++i) {
        coin(i)

        await new Promise(res => setTimeout(res, 1000))
    }
})()
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
kurokky profile image
kurokky(黒木シンタロー)

I thought of that method too, but since the pitch of the average rate shifts slightly, I use a correspondence table. (Added to the article.)

Thread Thread
 
lionelrowe profile image
lionel-rowe

Nice!

Collapse
 
toomuchdesign profile image
Andrea Carraro

Best article on dev.to!!

Collapse
 
ben profile image
Ben Halpern

This is neat

Collapse
 
safventure11000 profile image
Saf11000

cool! :)

Collapse
 
azlan_syed profile image
Azlan-Syed

Memories