Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Beep is a JavaScript toolkit for building browser-based synthesizers.

License

NotificationsYou must be signed in to change notification settings

stewdio/beep.js

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Beep.js

TL;DR
Create a synthesizer with one line of code:synth = new Beep.Instrument()Or plink away on the demo synth:http://beepjs.com.Tap the pulsing Play button for ajaunty music lesson.

MIDI controller support

Beep accepts input from MIDI controller keyboards via the brand newWeb MIDI API. (Just so we’re clear, this isvery awesome ;) You’ll need either Chrome 42 or Chrome 43+. For Chrome 42you must enable the Web MIDI API manually by visitingchrome://flags/#enable-web-midi and clickingEnable. For Chrome 43 andlater this is enabled by default. Simply plug in your modern MIDI controllerkeyboard via USB,then load up Beep. Your keys and pitch-bending wheel willwork just fine. And further support is coming soon!

Hackable

Beep is a JavaScript toolkit for building browser-based synthesizers usingthe WebAudio API. It takes a “batteries included” approach, meaning it bootsup ready to give you the audio equivalent of “Hello, World!” without too muchfuss. One line likesynth = new Beep.Instrument() will build a bundle ofTrigger interfaces, each with its ownVoices forNotes—that is, a pianokeyboard that you can begin banging on immediately. But what’s a softwarepiano that can’t play itself? Usesynth.scorePlay() to play the defaultscore provided for you. (And yes, you can always write your own scores!)

The blurb above and descriptions below include somesample code. If you’renew to hacking around in the browser you may be wondering where that code’ssupposed to go. Are you viewing this in a modern desktop browser? Then youcan open up your browser’sJavaScript Console and start hacking away rightnow. Here’s how:

Chrome: View → Developer → JavaScript Console, or⌥⌘J.
Safari: First,enable the Developer menu.Then, Develop → Show Error Console, or⌥⌘C.
Firefox: Tools → Web Developer → Web Console, or⌥⌘K.
Opera: View → Developer Tools → Opera Dragonfly,or⌥⌘I, then click on the Console tab.

Notes

Creating a new note is easy:n = new Beep.Note(). But unless you’re contentwith nothing but concert A’s blaring at 440Hz all day, you’re going to want tocreate other notes like so:new Beep.Note('E♭') ornew Beep.Note('5E♭')for an E♭ that’s in the 5th octave rather than the default 4th octave. So whatdoes that5E♭ give you anyway? An object like this:

{A:440,//  What Concert A are we tuned to?hertz:622.253,//  Frequency of the note.isFlat:true,//  Set if ♭. Similar: isSharp and isNatural.letter:"E",//  Explains itself, no?letterIndex:4,//  ['ABCDEFG'].indexOf(letter).midiNumber:75,//  Corresponding MIDI controller keyboard code.modifier:"♭",//  Set to ♭, ♮, or ♯.name:"E♭",//  Note name. Will include ♮.nameIndex:7,//  ['A♭','A♮','B♭','B♮','C♮'…].indexOf(name)nameSimple:"E♭",//  Note name. Will NOT include ♮.octaveIndex:5,//  On a standard piano, 0–8.pianoKeyIndex:55,//  On a standard piano, 0–87.tuning:"EDO12"//  Default: Equal Division of Octave into 12 steps.}

Flexible parameters
Sure, you can callnew Beep.Note('E♭') and accept the above defaultparameters that come with it. But you can also send an Object toNoteinstead of a String and set each of those parameters manually! No specificparam is required so just send what you need:

newBeep.Note({A:442,name:'E♭',octaveIndex:5})

By the numbers
Can we just throw all this named-note garbage out the window? Yes. Want theDevil’s note? Trynew Beep.Note(666). What does that give you?{ hertz: 666 } I happen to like named notes though. They provide a prettynice grid to work with, eh?

Easy ASCII
It might quell your anxieties to know thatNote will intelligently convertthe common# (number) into a proper (sharp) and will also accept alowercaseb as a substitue for (flat). There’s no need to use(natural) but it is in the code there should you desire to invoke it.

Smart conversion
If you commit a serious blunder likenew Beep.Note('B♯') don’t stress,Note will kindly assume you intendedNote('C♮') instead.(There is no B♯.)If you happen to be old school German then, yes, you can useH instead ofB. (Similarly, there is no H♯. Weirdo.)

Western tunings
Right now only western tunings are supported—I’m afraid that’s all I know howto work with. All note params pass throughNote.validateWestern() which doesthe above fancy logic. From there I’ve included support for two separatetunings:Just intonationandEqual temperament.More needs to be written on this topic for sure…

Bach up a second
So all that’s great, but aNote is just a mathematical model. (You’ll noticeit has noplay() method for example.) It doesn’t make any sound. For that wewill need aVoice.

Voices

How do you make aNote sing? Give it aVoice. Or rather—create aVoiceinitialized with aNote and maybe pass it anAudioContext to pipe thesound out to. Just as withNote the arguments forVoice are all optional.Providing none will yield aVoice with a defaultNote of 440Hz:

voice=newBeep.Voice()//  We’re running with defaults.voice.play()//  Listen to that pure 440Hz Concert A.voice.pause()//  Ok, we’ve had enough.

Note arguments
Voice will pass note-like arguments toNote. It doesn’t take an in-stateLiberal Arts degree to imagine whatnew Beep.Voice('2E♭') ornew Beep.Voice({ A: 442, name: 'E♭', octaveIndex: 2 }) might produce then.You could even trynew Beep.Voice(new Beep.Note('2E♭')) if you’re not intothat whole brevity thing, man.

Audio arguments
If you do not pass anAudioContext orGainNode toVoice it will createanAudioContext for itself. This is convenient because it meansVoice justworks (batteries-included, eh?) but there are hardware limits on the number ofAudioContexts you can create. We’ll see how to solve this later by creatinganInstrument and passing itsAudioContext to eachVoice.

Only fix what’s Baroque
I guess all the above is pretty cool, but having to typevoice.play() andvoice.pause() everytime I want to voice aNote is kind of a drag. Andthat’s whereTrigger comes in.

Triggers

We can dream up aNote, give it aVoice, but wouldn’t it be great if wehad some visible DOM Elements and Event Listeners working on our behalf?Behold, your default Concert A:t = new Beep.Trigger(). Simply creatinga newTrigger will also construct the DOM bits and listeners for you.No further fuss necessary.

Notes & Voices
As you may have guessed,Trigger will create aVoice for you and assign itaNote. Setting this at initialization time is trivial:new Beep.Trigger('E♭'). See theVoice description above to get an idea ofthe variation possible here. And it’s likewise trivial to alter theNote orVoice after creation.

Many Voices
Rather than one single voice,Trigger is setup to handle a whole Array ofthem. In fact, the defaultTrigger uses two voices: one employs a sine-waveoscillator at the intendedNote while a second employs a square-waveosciallator running one octave lower for a nice chunky Nintendo sound.Customizing your instance’screateVoices() method is the name of the game!

Audio arguments
Just likeVoice,Trigger is happy to ingest anAudioContext orGainNode argument but will make do without one if it has to. See the aboveVoice blurb for more details. Additionally you can pass it a Function…

Customizing Trigger’s createVoices() method
Upon initialization each instance of Trigger calls itscreateVoices()method. If you’re the type of gal that likes to annihilate mosquitos usingatom bombs then you can just overwriteBeep.Trigger.prototype.createVoices.Otherwise, why not pass a custom function during initialization like so:

vartrigger=newBeep.Trigger('2Eb',function(){this.voices.push(//  Let’s call this our “Foundation Voice”//  because it will sing the intended Note.newBeep.Voice(this.note,this.audioContext).setOscillatorType('sine').setAttackGain(0.4),//  This Voice will sing a Perfect 5th above the Foundation Voice.newBeep.Voice(this.note.hertz*3/2,this.audioContext).setOscillatorType('triangle').setAttackGain(0.1),//  This Voice will sing 2 octaves above the Foundation Voice.newBeep.Voice(this.note.hertz*4,this.audioContext).setOscillatorType('sawtooth').setAttackGain(0.01),//  This Voice will sing 1 octave below the Foundation Voice.newBeep.Voice(this.note.hertz/2,this.audioContext).setOscillatorType('square').setAttackGain(0.01))})

Many Triggers
Throw a few of these together and you have a mini-keyboard. What famousmovie theme does this keyboard play? Notice how we can optionally addkeyboard event listeners to bind characters toTriggers? Here we’veassigned the characters 1–5 to activate the five triggers respectively.

newBeep.Trigger('4G').addTriggerChar('1')newBeep.Trigger('4A').addTriggerChar('2')newBeep.Trigger('4F').addTriggerChar('3')newBeep.Trigger('3F').addTriggerChar('4')newBeep.Trigger('4C').addTriggerChar('5')

What if we had a convenient way to bundle theseTriggers together? Youguessed it:Instrument to the rescue.

Instruments

How simple is this?synth = new Beep.Instrument(). You can pass theconstructor either a DOM Element or a String representing the ID of a DOMElement and it will target that for the build. Otherwise it will just createits own. That one command gives you a default keyboard ofTriggers withVoices and so on. Pretty nifty, eh?

Triggers
Sure, upon creation your instance ofInstrument will runbuild() onitself, creating a default set ofTriggers. But it is so easy to overwritethis function with your own custom keyboard. (You should do this!) There is acorrespondingunbuild() method for removing all of itsTriggers. And thatmovie-theme keyboard from above? It comes built-in as well:

Beep.Instrument.prototype.buildCloseEncounters=function(){this.unbuild().newTrigger('4G','1').newTrigger('4A','2').newTrigger('4F','3').newTrigger('3F','4').newTrigger('4C','5')returnthis}

ThenewTrigger() convenience method creates a newTrigger, passes it theexistingAudioContext, and adds keyboard Event Listeners. Oh, my!

Customizing Trigger’s createVoices() method—Redux
You can also pass a customcreateVoices() method toInstrument and it willin turn pass that function to eachTrigger instance that it creates. See themainTrigger description above for details!

Scores

Instrument comes with a built-in score that you might recognize asDo Re Mi. In the demo you canclick the pulsing Play button to run it. This isequivalent toInstrument.scorePlay() in code. Check out the source to seehow we’re able to compose the melody and harmony separately andInstrument.scoreLoad() blends them together.

Composing
Scores are just Arrays ingested three entries at a time: 1. Delay time(relative to the previous command), 2.Trigger ID to engage, 3. Engagementduration. I find it’s easiest to write the durations in fractions like themusical notation they are replacing: ¼ = quarter note, ½ = half note, and soon. Here’s a sample from the default score:

melody=[36/4,'4C',6/4,//  Do[e]6/4,'4D',2/4,//  a2/4,'4E',5/4,//  deer6/4,'4C',2/4,//  A2/4,'4E',4/4,//  fe4/4,'4C',3/4,//  male4/4,'4E',4/4,//  deer

Further

In the future it might make more sense to separate Score into its own Class.Beep’s naming conventions could use some tightening. And there is definitely aneed for more explanation (and a demo) related to the difference betweenJust intonation andEqual temperament.And so much more to come. It’s early days.

About

Beep is a JavaScript toolkit for building browser-based synthesizers.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp