Good Vibrations

20

7

The sound of the theremin has been immortalized in The Beach Boys song Good Vibrations. Many also associate its sound with the theme for the original series of Star Trek, though apparently it was a soprano's emulation.

This challenge requires you to implement a theremin.

Input

  • Take 2 dimensional input from a mouse or other input device (e.g. you could use a joystick), which will produce a tone from an audio output device as follows:
    • increasing x will increase the frequency of the tone. Note that frequency increases exponentially with musical note, so you must implement a linear relationship between mouse x position and the musical note, and
    • increasing y will increase the volume of the tone.
  • There appears to be confusion regarding the waveform produced by a real theremin, so for simplicity, a sine wave (or close approximation thereof) must be used.

Rules

  • The tone produced must have at least a 2-octave range. More range is acceptable. A-440 must lie within the range.
  • In order to create the audible appearance of continuously variable frequency and amplitude, the range of values considered in both dimensions from the input device must be at least 500 Implementations may open a window (at least 500x500 pixels) to read input from mouse cursor position. Or without opening a window, coordinates may be read directly from the mouse or other input device.
  • There must be a simple means to stop the program - key-combination, mouse-click or other common input device. CTRL-c is sufficient.
  • Any standard libraries may be used, as long as they do not totally implement the solution with no other work required.
  • Standard rules for Code Golf and I/O
  • You may stop by having the mouse or input device lose focus on the input box.

Notes

  • Because the output tone is dynamically-generated, care must be take to ensure the tone is a continuous waveform; that is there are no audible clicks or pops caused by sudden changes of phase or amplitude.
  • You may limit the input size zone to 500 by 500 but it may be bigger.

This is , so the shortest answer in any language wins.

Special thanks

Special thanks to Digital Trauma for making this challenge and posting it in the Secret Santa's Sandbox. I have made a few edits and here is the original post.

Christopher

Posted 2017-03-30T15:23:00.673

Reputation: 3 428

Answers

10

JavaScript ES6, 215 188 bytes

This seems to work well in Chrome and Edge. Firefox and Safari not so much.

with(new AudioContext)o=createOscillator(onmousemove=e=>{o.frequency.value=9/innerWidth*e.x**2,v.gain.value=1-e.y/innerHeight}),v=createGain(),v.connect(destination),o.start(),o.connect(v)

Saved 27 bytes thanks to @darrylyeo

Try it online!

with(new AudioContext)o=createOscillator(onmousemove=e=>{o.frequency.value=9/innerWidth*e.x**2,v.gain.value=1-e.y/innerHeight}),v=createGain(),v.connect(destination),o.start(),o.connect(v)
<button onClick="o.stop()">Stop</button>

powelles

Posted 2017-03-30T15:23:00.673

Reputation: 1 277

1That is pretty good! I had way too much fun – Christopher – 2017-03-30T22:34:32.370

2

Thanks. I think it's even more fun with a with a square wave

– powelles – 2017-03-31T00:08:21.923

1Trying it out and about lost an eardrum – Christopher – 2017-03-31T00:18:09.243

o.type='sine' is unnecessary since it's the default. You can simplify document.onmousemove to just onmousemove. – darrylyeo – 2017-03-31T02:22:36.433

Golfed from 215 to 188 bytes: with(new AudioContext)o=createOscillator(onmousemove=e=>{o.frequency.value=9/innerWidth*e.x**2,v.gain.value=1-e.y/innerHeight}),v=createGain(),v.connect(destination),o.start(),o.connect(v) – darrylyeo – 2017-03-31T02:22:52.610

Thanks. I didn't know about with. That is some cool stuff. – powelles – 2017-03-31T02:37:13.730