From ce20b7d02c2f8e09195b4ff015609e3fd4848863 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Thu, 9 Feb 2023 00:01:39 -0500 Subject: [PATCH] Piano can now play square waves --- examples/piano/main.go | 69 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/examples/piano/main.go b/examples/piano/main.go index da01741..d5d39c5 100644 --- a/examples/piano/main.go +++ b/examples/piano/main.go @@ -1,5 +1,7 @@ package main +import "math" +import "errors" import "github.com/faiface/beep" import "github.com/faiface/beep/speaker" import "github.com/faiface/beep/generators" @@ -13,7 +15,7 @@ import _ "git.tebibyte.media/sashakoshka/tomo/backends/x" const sampleRate = 44100 const bufferSize = 256 var tuning = music.EqualTemparment { A4: 440 } - +var waveform = 0 var playing = map[music.Note] *beep.Ctrl { } func main () { @@ -27,8 +29,20 @@ func run () { container := basicElements.NewContainer(basicLayouts.Vertical { true, true }) window.Adopt(container) + controlBar := basicElements.NewContainer(basicLayouts.Horizontal { true, false }) label := basicElements.NewLabel("Play a song!", false) - container.Adopt(label, false) + controlBar.Adopt(label, true) + waveformButton := basicElements.NewButton("Sine") + waveformButton.OnClick (func () { + waveform = (waveform + 1) % 2 + switch waveform { + case 0: waveformButton.SetText("Sine") + case 1: waveformButton.SetText("Square") + } + }) + controlBar.Adopt(waveformButton, false) + container.Adopt(controlBar, false) + piano := fun.NewPiano(3, 5) container.Adopt(piano, true) piano.OnPress(playNote) @@ -48,8 +62,11 @@ func stopNote (note music.Note) { } func playNote (note music.Note) { - streamer, err := generators.SinTone(sampleRate, int(tuning.Tune(note))) - if err != nil { panic(err.Error()) } + var streamer beep.Streamer + switch waveform { + case 0: streamer, _ = generators.SinTone(sampleRate, int(tuning.Tune(note))) + case 1: streamer, _ = SquareTone(sampleRate, int(tuning.Tune(note))) + } stopNote(note) speaker.Lock() @@ -57,3 +74,47 @@ func playNote (note music.Note) { speaker.Unlock() speaker.Play(playing[note]) } + +// https://github.com/faiface/beep/blob/v1.1.0/generators/toner.go +// Adapted to be a square wave instead + +type toneStreamer struct { + stat float64 + delta float64 +} + +func SquareTone (sr beep.SampleRate, freq int) (beep.Streamer, error) { + if int(sr) / freq < 2 { + return nil, errors.New ( + "square tone generator: samplerate must be at least " + + "2 times greater then frequency") + } + tone := new(toneStreamer) + tone.stat = 0.0 + srf := float64(sr) + ff := float64(freq) + steps := srf / ff + tone.delta = 1.0 / steps + return tone, nil +} + +func (tone *toneStreamer) nextSample () (sample float64) { + if tone.stat > 0.5 { + sample = 1 + } else { + sample = 0 + } + _, tone.stat = math.Modf(tone.stat + tone.delta) + return +} + +func (tone *toneStreamer) Stream (buf [][2]float64) (int, bool) { + for i := 0; i < len(buf); i++ { + s := tone.nextSample() + buf[i] = [2]float64{s, s} + } + return len(buf), true +} +func (tone *toneStreamer) Err () error { + return nil +}