~whereswaldon/chipalee

d2ed91be14f410e4b39e847ab02018864823a074 — Chris Waldon 1 year, 9 months ago bbef9d8
main: visualize playing notes

Signed-off-by: Chris Waldon <christopher.waldon.dev@gmail.com>
1 files changed, 58 insertions(+), 17 deletions(-)

M main.go
M main.go => main.go +58 -17
@@ 1,3 1,5 @@
// Part of this file is licensed:
//
// Copyright 2019 The Oto Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");


@@ 11,23 13,30 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// The remainder is available under the terms of the UNLICENSE.

package main

import (
	"flag"
	"image"
	"image/color"
	"io"
	"log"
	"math"
	"strings"
	"time"

	"gioui.org/app"
	"gioui.org/f32"
	"gioui.org/font/gofont"
	"gioui.org/io/key"
	"gioui.org/io/system"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/op/clip"
	"gioui.org/op/paint"
	"gioui.org/widget"
	"gioui.org/widget/material"
	"github.com/hajimehoshi/oto/v2"


@@ 145,50 154,47 @@ const (
	BF5 = AS5
	B5  = 987.8

	IdxBF4 = IdxAS4
	IdxDF5 = IdxCS5
	IdxEF5 = IdxDS5
	IdxGF5 = IdxFS5
	IdxAF5 = IdxGS5
	IdxBF5 = IdxAS5
)

const (
	IdxA4 = iota
	IdxAS4
	IdxBF4
	IdxB4
	IdxC5
	IdxCS5
	IdxDF5
	IdxD5
	IdxDS5
	IdxEF5
	IdxE5
	IdxF5
	IdxFS5
	IdxGF5
	IdxG5
	IdxGS5
	IdxAF5
	IdxA5
	IdxAS5
	IdxBF5
	IdxB5
)

var freqs = []float64{
	IdxA4:  A4,
	IdxAS4: AS4,
	IdxBF4: BF4,
	IdxB4:  B4,
	IdxC5:  C5,
	IdxCS5: CS5,
	IdxDF5: DF5,
	IdxD5:  D5,
	IdxDS5: DS5,
	IdxEF5: EF5,
	IdxE5:  E5,
	IdxF5:  F5,
	IdxFS5: FS5,
	IdxGF5: GF5,
	IdxG5:  G5,
	IdxGS5: GS5,
	IdxAF5: AF5,
	IdxA5:  A5,
	IdxAS5: AS5,
	IdxBF5: BF5,
	IdxB5:  B5,
}



@@ 261,6 267,26 @@ func keySet() key.Set {

}

// Pipe represents one pipe of the virtual organ.
type Pipe struct {
	player  oto.Player
	playing bool
	since   time.Time
}

func (p *Pipe) Play(now time.Time) {
	if !p.playing {
		p.since = now
	}
	p.playing = true
	p.player.Play()
}

func (p *Pipe) Pause() {
	p.playing = false
	p.player.Pause()
}

func run(w *app.Window) error {
	log.Println("run start")
	c, ready, err := oto.NewContext(*sampleRate, *channelNum, *bitDepthInBytes)


@@ 268,13 294,13 @@ func run(w *app.Window) error {
		return err
	}

	players := make([]oto.Player, len(freqs))
	toggleIndex := func(idx int, event key.Event) {
	players := make([]Pipe, len(freqs))
	toggleIndex := func(idx int, event key.Event, now time.Time) {
		if idx >= len(players) {
			return
		}
		if event.State == key.Press {
			players[idx].Play()
			players[idx].Play(now)
		} else {
			players[idx].Pause()
		}


@@ 322,7 348,7 @@ func run(w *app.Window) error {
								continue
							}
							for _, idx := range playingFrom[idx] {
								toggleIndex(idx, event)
								toggleIndex(idx, event, gtx.Now)
							}
						}
					}


@@ 330,6 356,21 @@ func run(w *app.Window) error {
						Tag:  w,
						Keys: keySet,
					}.Add(gtx.Ops)

					width := float32(gtx.Constraints.Max.X) / float32(len(players))
					rect := clip.Rect{
						Max: image.Point{
							X: int(width),
							Y: gtx.Constraints.Max.Y,
						},
					}.Op()
					for i, pipe := range players {
						if pipe.playing {
							offset := op.Offset(f32.Point{X: width * float32(i)}).Push(gtx.Ops)
							paint.FillShape(gtx.Ops, color.NRGBA{R: 200, A: 100}, rect)
							offset.Pop()
						}
					}
				}
				// This editor is needed for JS to properly deliver key events
				// to us.


@@ 343,7 384,7 @@ func run(w *app.Window) error {
			ready = nil
			audioInit = true
			for idx, f := range freqs {
				players[idx] = c.NewPlayer(NewSineWave(f))
				players[idx] = Pipe{player: c.NewPlayer(NewSineWave(f))}
			}
			log.Println("organ initialized")