tone() question..

jim lee

Well-known member
Running a Teensy 3.2, still have about a dozen of them.I remember being able to do tone() on multiple pins. How many tones can I do at one time?

-jim lee
Thanks! I was hoping for more. The idea was MIDI to Tone so it would work on standard Arduinos at least for single voices. But I see you're holding out a tempting bit of tonal candy here..
I'd recommend using analogWriteFrequency() and analogWrite(). On Teensy 3.2 you have 3 PWM timers, so you can have 3 independent frequencies this way if you choose the correct pins. Details with which timers control which pins can be found here: (scroll down to "PWM Frequency")

On Teensy 4.0 you get 19 independent PWM timers, so up to 19 independent frequencies.

Also keep in mind analogWriteFrequency() can accept either integer or float for the frequency, so you're not limited to integers which can cause slightly out of tune for the lower notes.

And on both Teensy 3.2 and 4.0, you can get 1 more with tone(). But the tone() code only supports a single frequency. Internally tone() uses IntervalTimer, so if you *really* wanted to dive into the low-level tone() code there is at least a theoretical possibility to expand it to 4 voices. But using analogWriteFrequency() is much simpler and doesn't burn CPU or risk slightly off waveforms if something else you do imposes interrupt latency.
You can also of course use the audio library. Teensy 3.2 can synthesize and mix dozens of waveforms and Teensy 4.0 can handle hundreds of voices. You can output the final mixed result using the DAC pin on Teensy 3.2 or MSQ on Teensy 4.0. Or use the audio shield or PT8211 DAC for higher quality. With the audio library you can control the waveform amplitude, phase, shape (sine, triangle, sawtooth, etc) of each waveform, so much more musical than just mixing square waves of fixed amplitued. The library also gives modulated waveforms (using other waveforms as your LFOs) and a ton of other features. You also don't need external circuitry to mix all the waveforms, as it can be done with DSP inside the audio library. Yeah, it's Teensy-specific, so if you're looking to write code that can run on all Arduino compatible boards, you don't get that sort of lowest common denominator style. But isn't as many waveforms as you want, mixed entire in software at any relative amplitues, a pretty compelling feature?
Something else you might consider when writing code using tone() is almost every Arduino compatible board has a slightly different implementation. Behavior of tone() differs when you suddenly stop the output with noTone() rather than letting it finish of the pre-determined amount of time. You can also get different behavior across boards if your code calls tone() to start a different frequency while a prior tone is still playing.

On Teensy, the tone() implementation handles those cases by completing the current waveform cycle. So if you're playing a 100 Hz tone, which has a 10ms period and you call noTone() at 6ms into the cycle, on Teensy you will not get 5ms high and then 1ms low (giving a half cycle of 500 Hz). But on other boards, you might get that 500 Hz half cycle behvior. Likewise for switching between tones, if you were playing 100 Hz and you switch to 140 Hz at the 6ms point within the cycle, Teensy will complete the 10ms cycle and then seamlessly begin the 7.14ms cycle so you get only 100 Hz (plus square wave harmonics) followed by 140 Hz (and its square wave harmonics).

Expect other tone() implementations to give you a brief moment of some other frequency in those live transition cases. If your program calls tone() rapidly, you can end up with quite different sound due to these differences in the tone() implementation. Maybe you might even like that glitchy effect. Just know that tone() is not consistent across all Arduino compatible boards. Those live transition cases are handled quite differently on different boards.
Yeah, it is. I always suspected this kind of stuff was in my little 3.2s but never was in "the area" to learn about it. This all started with writing a silly game for my handheld and wanting short tunes to play on the piezo speaker when stuff happened. I'd written a library based on tone() I could program with notes & rests to make the tunes but it was a nightmare. Then I thought, huh I have a MIDI keyboard, why not play them there and decode the MIDI file to program my tone() library? After a LOT of learning curve about MIDI etc. I got it working! But I have to be careful to only have the one voice.

And as soon as I got it working, I wanted more..

Then you guys start dangling all this..
Ok, so to start. I have MIDI file on SD card, how do I play it on my piezo speaker using these libraries? What do I need to grab?