5684185+vsariola@users.noreply.github.com ec222bd67d feat(tracker): oscilloscope and LUFS / true peak detection
In addition to the oscilloscope and loudness/peak detections, this
commit refactors all the channels between components (i.e.
ModelMessages and PlayerMessages) etc. into a new class Broker. This
was done because now we have one more goroutine running: a Detector,
where the loudness / true peak detection is done in another thread.
The different threads/components are only aware of the Broker and
communicate through it. Currently, it's just a collection of
channels, so it's many-to-one communication, but in the future,
we could change Broker to have many-to-one-to-many communication.

Related to #61
2024-11-02 15:08:09 +02:00

89 lines
2.3 KiB
Go

package main
import (
"flag"
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"runtime/pprof"
"gioui.org/app"
"github.com/vsariola/sointu/cmd"
"github.com/vsariola/sointu/oto"
"github.com/vsariola/sointu/tracker"
"github.com/vsariola/sointu/tracker/gioui"
"github.com/vsariola/sointu/tracker/gomidi"
)
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
var memprofile = flag.String("memprofile", "", "write memory profile to `file`")
var defaultMidiInput = flag.String("midi-input", "", "connect MIDI input to matching device name")
var firstMidiInput = flag.Bool("first-midi-input", false, "connect MIDI input to first device found")
func main() {
flag.Parse()
var f *os.File
if *cpuprofile != "" {
var err error
f, err = os.Create(*cpuprofile)
if err != nil {
log.Fatal("could not create CPU profile: ", err)
}
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal("could not start CPU profile: ", err)
}
}
audioContext, err := oto.NewContext()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
recoveryFile := ""
if configDir, err := os.UserConfigDir(); err == nil {
recoveryFile = filepath.Join(configDir, "Sointu", "sointu-track-recovery")
}
midiContext := gomidi.NewContext()
defer midiContext.Close()
midiContext.TryToOpenBy(*defaultMidiInput, *firstMidiInput)
broker := tracker.NewBroker()
model, player := tracker.NewModelPlayer(broker, cmd.MainSynther, midiContext, recoveryFile)
detector := tracker.NewDetector(broker)
go detector.Run()
if a := flag.Args(); len(a) > 0 {
f, err := os.Open(a[0])
if err == nil {
model.ReadSong(f)
}
f.Close()
}
trackerUi := gioui.NewTracker(model)
processor := tracker.NewProcessor(player, midiContext, trackerUi)
audioCloser := audioContext.Play(processor)
go func() {
trackerUi.Main()
audioCloser.Close()
if *cpuprofile != "" {
pprof.StopCPUProfile()
f.Close()
}
if *memprofile != "" {
f, err := os.Create(*memprofile)
if err != nil {
log.Fatal("could not create memory profile: ", err)
}
defer f.Close() // error handling omitted for example
runtime.GC() // get up-to-date statistics
if err := pprof.WriteHeapProfile(f); err != nil {
log.Fatal("could not write memory profile: ", err)
}
}
os.Exit(0)
}()
app.Main()
}