4

I am making a software audio synthesizer and so far i've managed to play a single tone at once.

My goal was to make it polyphonic, i.e when i press 2 keys both are active and produce sound (i'm aware that a speaker can only output one waveform at a time).

From what i've read so far, to achieve a pseudo-polyphonic effect what you are supposed do, is to add the tones to each other with different amplitudes.

The code i have is too big to post in it's entirety but i've tested it and it's correct (it implements what i described above, as for whenever it's the correct thing to do i'm not so sure anymore)

Here is some pseudo-code of my mixing

sample = 0.8 * sin(2pi * freq[key1] * time) + 0.2 * sin(2pi * freq[key2] * time)

The issue i have with this approach is that when i tried to play C C# it resulted in a wierd wobble like sound with distortions, it appears to make the entire waveform oscillate at around 3-5 Hz.

I'm also aware that this is the "correct" behavior because i graphed a scenario like this and the waveform is very similar to what i'm experiencing here.

I know this is the beat effect and that's what happens when you add two tones close in frequency but that's not what happens when you press 2 keys on a piano, which means this approach is incorrect.

Just for test i made a second version that uses stereo configuration and when a second key is pressed it plays the second tone on a different channel and it produces the exact effect i was looking for.

Here is a comparison

Any help would be appreciated, but don't say it's impossible because all of the serious synthesizers can achieve this effect

  • What are the values of freq[key1] and freq[key2]? – Ray Butterworth Dec 11 '19 at 15:28
  • in my case 220 and 233.08.. – robeddieson Dec 11 '19 at 15:30
1

What's not correct is your assumption of how a piano works. A piano does not produce pure sine waves, which is what you are attempting to do.

The majority of piano notes are generated by felt hammers hitting multiple detuned wound metal strings. (Note that a correctly tuned piano will have each of the three strings at a different pitch. The centre string will be bang on the note, the first string slightly lower and the third string slightly higher.) The sounds this makes are possibly as far away from being a pure sine as it is possible to get. The harmonics, timbres and overtones you are listening to are incredibly complex. Sure if you break this down into it's individual frequency components at some point you are probably going to find a small sine component beating with another sine component, but in reality the complexity of the added waveforms is going to mask any beating very comprehensively.

You are, however on the right track, however you need to make your syntheised sounds far more complex and layered in order to be able to generate listenable sounds. And, of course you are going to get beating with a minor second interval. The depth of that beating will depend on how complex your overall harmonic structure is within each individual synthesised note.

What you are experiencing now is exactly what I would expect to hear with these sorts of tones and this sort of an interval. You just need to work out how to make the overall sound much more complex and layered in order to mask the beating sound at this particular interval.

| improve this answer | |
  • i understand the above but i still don't quite get why doesn't it produce the same sound when doing "real" polyphony with stereo (second wav file) . i know its mostly sinewaves (tried it with a complex tone with a few harmonic component) but the result wasnt much different how come i get a nice harmonic waveform irl but wierd wobble with addition, what transformation can i apply to imitate the irl result.? – robeddieson Dec 11 '19 at 11:22
  • Just in addition to my answer above, check out this video by Jacob Collier - specifically around 44:00 which explains some of the quirks of piano tuning. youtube.com/… – Mark Dec 11 '19 at 12:09
  • It's mostly down to the fact that you are playing a minor second interval. Try some different intervals - specifically perfect 4ths and 5th. - try some Major 3rds and 6ths as well - see what you get. – Mark Dec 11 '19 at 12:11
  • You should also investigate 'temperament' - specifically "Equal Temperament". This will also explain this a bit better. en.wikipedia.org/wiki/Equal_temperament – Mark Dec 11 '19 at 12:15
  • thanks for resources will read up soon but i dont think you anwsered my question about why it sounds different. by adding tones we are supposed to imitate what the waves do irl but irl there is harmonic sound and added waves make beat so either thats not what happens or im misunderstanding something – robeddieson Dec 11 '19 at 12:22
0

There are notes that go well together, and notes that don't.

Notes whose frequencies are a simple integer ratio go well together, such as: 1:1 (unison), 1:2 (octave), 2:3 (perfect fifth).

Notes whose frequencies don't have a nice relationship sound dissonant, such as 220:233.08.

Copy the following into a test.html file and try it with your browser. The fourth example will sound "wrong".

<!DOCTYPE html>
<body>
    <button onclick="play(220); play(220)"></button>
    <button onclick="play(220); play(440)"></button>
    <button onclick="play(220); play(330)"></button>
    <button onclick="play(220); play(233.08)"></button>
</body>
<script> "use strict"
var index
var buttons = document.getElementsByTagName("button")
for (index=0; buttons[index]; ++index)
    buttons[index].innerHTML += buttons[index].onclick
var play = (function() {
    var MIN_VOLUME = .00001
    var MAX_VOLUME = .2
    var RAMP = .04
    var DURATION = 4
    var audio
    return function(frequency) {
        if (!audio) audio = new(window.AudioContext || window.webkitAudioContext)()
        var oscillator = audio.createOscillator()
        var gain = audio.createGain()
        var time = audio.currentTime
        oscillator.connect(gain).connect(audio.destination)
        oscillator.frequency.value = frequency
        gain.gain.value = 0
        gain.gain.exponentialRampToValueAtTime(MAX_VOLUME, time+RAMP)
        gain.gain.exponentialRampToValueAtTime(MIN_VOLUME, time+RAMP+DURATION)
        oscillator.start()
        oscillator.stop(time+RAMP+DURATION)
    }
})()
</script>
</html>
| improve this answer | |
  • Inline executable code is potentially highly dangerous. I don't think you'll ever see SE adopt that one. – Tetsujin Dec 11 '19 at 15:52
  • i know playing f and f*2 will result in a harmonic sound but in a scale notes are pow(pow(2, 1/12), note) so arent they exactly that way so they sound good – robeddieson Dec 11 '19 at 15:53
  • Yes, the standard notes on a piano are tuned to be tuned to the twelfth root of two apart. But even on a piano, playing two adjacent keys produces dissonance. Read about Semitone — Wikipedia. And listen to this example of Minor_Second — Wikipedia. You'll hear that yours sounds just as it's supposed to. – Ray Butterworth Dec 11 '19 at 16:12
  • @Tetsujin, it's called "snippet" in other SE sites (e.g. Stack Overflow itself). The code is wrapped with <!-- begin snippet: … end snippet -->, and viewers can safely run it. – Ray Butterworth Dec 11 '19 at 16:26
0

So what you get when playing the mono version is a phase cancellation - this happens always when you mathematically add two identical waveforms with different frequencies (i.e. when the frequency ratio is not an integer). Since your frequencies are 220 and 233 Hz this will result in the wobble that you observed. In the second case you route each note through a different channel, therefore the waveforms do not interact at the signal level - and phase cancellation does not happen in the air (well at least not to the same extent as in electric currents), hence the sound is different.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.