playdate.sound.track:addNote uses MIDI, but playdate.sound.synth:playNote uses pitch?

Hello, I'm just wondering if anybody knows why:

  • synth:playNote can play arbitrary frequencies...
  • and synth objects can be used as instruments for tracks...
  • but track:addNote only supports MIDI notes?

I see this in both the Lua and C APIs and was curious to know why this is the case?
I'm asking because I'm trying to replicate arbitrary 80's coin-op music which was often a series of notes that didn't directly correspond to the musical scale that MIDI uses.

For example, this is fine:

local synth = snd.synth.new(snd.kWaveSine)
synth:playNote(1800, 0.5, 1)

But this doesn't work

local track = snd.track.new()
track:setInstrument(synth:copy())
track:addNote(1, 1800, 2)
track:addNote(2, 2000, 2)
track:addNote(3, 1600, 2)
seq:addTrack(track)
seq:play()

But this is fine

local track = snd.track.new()
track:setInstrument(synth:copy())
track:addNote(1, "C4", 2)
track:addNote(2, "B4", 2)
track:addNote(3, "A4", 2)
seq:addTrack(track)
seq:play()

I'm sure somebody has asked this in the past, but cursory forum search didn't find an answer. Thanks!

Originally, playdate.sound.synth just had a playNote() function that took a frequency argument. At some point I also wanted to be able to use MIDI note numbers so I added playMIDINote() as an alternative, since the code can't tell from context whether the number you give it is a frequency or a note and I couldn't reuse the same function like I did when I added support there for note names (A4 etc.). Anyway, the important thing here is that the MIDI note doesn't have to be a whole number: 60.5 is halfway between C3 and C#3.

When I implemented track:addNote() I didn't think to call it addMIDINote instead, and I probably should have for consistency. :confused: If you give it a number in the second argument it's interpreted as a MIDI note instead of a frequency. To convert frequency to MIDI note (in the C3 middle C standard) you can use

function freqToNote(f)
  return 39.863137 * math.log(f) - 36.376317
end

1600 -> 91.350
1800 -> 93.389
2000 -> 95.213

3 Likes

Oh superb thank you Dave! I shall immediately stop reimplementing sequence :slight_smile:

Could I suggest that this little hint could be included in the Inside Play.Date documentation, like the other handy emebbed hints in there?

I'm a programmer, not a musician alas so the conversion between arbitrary frequencies and musical scale escaped me.

Thank you!

1 Like