Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 97 additions & 0 deletions doit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package main

import (
"fmt"
"time"

mid "jack-peak-meter/midi"

"github.com/pkg/errors"
)

// const volumeThreshold = 10
// const lowThreshold = 5

const volumeThreshold = 60

// const volumeThreshold = 70
const lowThreshold = 40

// if the new note is higher than the previous one, and it's been more than 200 ms since the last increase, this is a peak. if it's also above some threshold
const waitTime = 200 * time.Millisecond

var lastTimePeak *time.Time
var lastTimeValley *time.Time

var hitCount = 0

var t = time.Now()

var storedValues = []float32{}

func processFrames(value float32, percentage int) {
storedValues = append(storedValues, value)

// fmt.Println(value)

now := time.Now()
if lastTimePeak == nil {
if percentage >= volumeThreshold {
lastTimePeak = &now
hit(percentage)
hitCount++
// ptof(hitCount)
}
return
}

if time.Since(*lastTimePeak) < waitTime {
return
}

if lastTimeValley == nil {
if percentage < lowThreshold {
lastTimeValley = &now
}
return
}

if time.Since(*lastTimeValley) < waitTime {
return
}

diff := lastTimePeak.Sub(*lastTimeValley)
waitingForValley := diff > 0

if waitingForValley {
if percentage < lowThreshold {
// fmt.Println(percentage)
lastTimeValley = &now
}
return
}

if percentage >= volumeThreshold {
lastTimePeak = &now
hit(percentage)
hitCount++
// ptof(hitCount)
}
}

func hit(percentage interface{}) {
go func() {
err := mid.PlayNotes(midiOut, []mid.MidiNote{
{
Note: 50,
Velocity: 127,
},
}, time.Millisecond*10)

if err != nil {
fmt.Println(errors.Wrap(err, "error playing midi note"))
}

// ptof(percentage)
}()
}
9 changes: 8 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,11 @@ module jack-peak-meter

go 1.12

require github.com/xthexder/go-jack v0.0.0-20201026211055-5b07fb071116
require (
github.com/pkg/errors v0.9.1
github.com/rakyll/portmidi v0.0.0-20201020180702-d436ceaa537a
github.com/xthexder/go-jack v0.0.0-20220805234212-bc8604043aba
gitlab.com/gomidi/midi v1.23.7
gitlab.com/gomidi/midi/v2 v2.0.25
gitlab.com/gomidi/portmididrv v0.7.1
)
16 changes: 14 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,14 @@
github.com/xthexder/go-jack v0.0.0-20201026211055-5b07fb071116 h1:03B3T3Dx1V/ZgapsHWtiyUtd6fGLVYNE8G4EYWoluRE=
github.com/xthexder/go-jack v0.0.0-20201026211055-5b07fb071116/go.mod h1:0UTXja5DHE3Z5tqm0WxYwpsclGdma/82Vw1JszrfzOE=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rakyll/portmidi v0.0.0-20170620004031-e434d7284291/go.mod h1:tO1ylmFo6+hnYFvj/fd92q30wkNQwgWC/8mcHq0KkQU=
github.com/rakyll/portmidi v0.0.0-20201020180702-d436ceaa537a h1:+qeh9b4LlO8AYVvm+TG4OXDRwBynTLk82t0HDBBBOQ8=
github.com/rakyll/portmidi v0.0.0-20201020180702-d436ceaa537a/go.mod h1:xKffaBd7e1YUoLpR2azvJqkxEdUDNGNDMlsUNdv6Bcs=
github.com/xthexder/go-jack v0.0.0-20220805234212-bc8604043aba h1:QighQ8fJJOqipXXurg9WghoImtvl7CHTpe21GDYdIkk=
github.com/xthexder/go-jack v0.0.0-20220805234212-bc8604043aba/go.mod h1:T6DswVPJzBW/Xg64l/gohXVgSW81GwXyMws1fkqxlUg=
gitlab.com/gomidi/midi v1.23.5/go.mod h1:3ohtNOhqoSakkuLG/Li1OI6I3J1c2LErnJF5o/VBq1c=
gitlab.com/gomidi/midi v1.23.7 h1:I6qKoIk9s9dcX+pNf0jC+tziCzJFn82bMpuntRkLeik=
gitlab.com/gomidi/midi v1.23.7/go.mod h1:3ohtNOhqoSakkuLG/Li1OI6I3J1c2LErnJF5o/VBq1c=
gitlab.com/gomidi/midi/v2 v2.0.25 h1:dkzVBqbaFHjyWwP71MrQNX7IeRUIDonddmHbPpO/Ucg=
gitlab.com/gomidi/midi/v2 v2.0.25/go.mod h1:quTyMKSQ4Klevxu6gY4gy2USbeZra0fV5SalndmPfsY=
gitlab.com/gomidi/portmididrv v0.7.1 h1:4+mX7HlxbD+JvprJl5pigj1pRxxPXzuSgLIiyzAIydY=
gitlab.com/gomidi/portmididrv v0.7.1/go.mod h1:H+WVjQPG4D5YJ6+fGKv0apxHN6qbXbNce/3oxZaPSMY=
110 changes: 90 additions & 20 deletions jack-peak-meter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"unsafe"

"github.com/xthexder/go-jack"
"gitlab.com/gomidi/midi"
)

const (
Expand Down Expand Up @@ -63,6 +64,7 @@ func (v *visualizer) Start() error {
// trying to establish JACK client
for i := 0; i < 1000; i++ {
clientName = fmt.Sprintf("spectrum analyser %d", i)
// v.client, status = jack.ClientOpen(clientName, jack.NullOption)
v.client, status = jack.ClientOpen(clientName, jack.NoStartServer)
if status == 0 {
break
Expand Down Expand Up @@ -105,7 +107,7 @@ func (v *visualizer) Start() error {

// print warning if # channels < # found
if v.channels < len(v.srcPortNames) {
fmt.Printf(">> Capturing the first %d channels of %d found <<\r", v.channels, len(v.srcPortNames))
printfe(">> Capturing the first %d channels of %d found <<\r", v.channels, len(v.srcPortNames))
}

// registering audio channels inputs and connecting them automatically to system monitor output
Expand All @@ -122,29 +124,29 @@ func (v *visualizer) Start() error {
return fmt.Errorf("Failed connecting port \"%s\" to \"%s\"\n", srcPortName, dstPortName)
}
if v.verbose {
fmt.Printf("connected port \"%s\" to \"%s\"\n", srcPortName, dstPortName)
printfe("connected port \"%s\" to \"%s\"\n", srcPortName, dstPortName)
}
}

fmt.Print(disableCursor) // disablingCursorblink
fmt.Print("\n")

interrupted := make(chan bool)

// signal handler
sigChan := make(chan os.Signal, 2)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-sigChan
fmt.Println("custom shutdown 1")
v.shutdown()
interrupted <- true

}()

buffer := int(v.client.GetBufferSize())
v.additionalBuffer = v.calculateAdditionalBuffer(buffer)
// buffer := int(v.client.GetBufferSize())
// v.additionalBuffer = v.calculateAdditionalBuffer(buffer)

<-interrupted

printe(disableCursor) // disablingCursorblink
printe("\n")
return nil
}

Expand All @@ -162,11 +164,21 @@ func getHighestSpread(samples []jack.AudioSample) jack.AudioSample {
return winner
}

var processCounter = 0

// JACK callback
func (v *visualizer) process(nframes uint32) int {
counter += 1
for i, port := range v.PortsIn {
processCounter++
// fmt.Printf("Process counter: %d\n", processCounter)

// fmt.Println("length of portin", len(v.PortsIn))

// for i, port := range v.PortsIn {
for i, port := range v.PortsIn[0:1] {
// for i, port := range v.PortsIn[0:1] {
samples := port.GetBuffer(nframes)
// fmt.Println(port)

highest := float32(getHighestSpread(samples))
highest *= float32(v.amplifer)
Expand All @@ -180,12 +192,12 @@ func (v *visualizer) process(nframes uint32) int {
termWidth, termHeight := getTermWidthHeight()

if termHeight < v.channels {
fmt.Printf(">> Not sufficient space for bars <<\r")
printfe(">> Not sufficient space for bars <<\r")
} else {
v.printBar(v.getAvg(i), termWidth, i)

if i+1 != v.channels { // do not print newline for last bar
fmt.Print("\n")
printe("\n")
}
v.avgMain[i] = 0
}
Expand All @@ -195,7 +207,7 @@ func (v *visualizer) process(nframes uint32) int {
if counter >= v.additionalBuffer {
counter = 0
for i := 1; i < v.channels; i++ {
fmt.Print(moveCursorUp)
printe(moveCursorUp)
}
}

Expand All @@ -204,8 +216,14 @@ func (v *visualizer) process(nframes uint32) int {

// JACK callback
func (v *visualizer) shutdown() {
fmt.Print(enableCursor + "\n")
v.client.Close()
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()

printe(enableCursor + "\n")
// v.client.Close()
}

func newVisualizer(channels, offset, buffer int, amplifier float64, portMatches portStrings, verbose, printValues, printChnIdx, printNames bool) visualizer {
Expand Down Expand Up @@ -311,7 +329,9 @@ func (v *visualizer) printBar(value float32, width, chanNumber int) {
bar += fillBlocks[0] // empty block fill
}

fmt.Print(bar + "| ")
printe(bar + "| ")

processFrames(value, fullBlocks)
}

type winsize struct {
Expand All @@ -336,7 +356,18 @@ func getTermWidthHeight() (x, y int) {
return
}

var midiOut midi.Out

func main() {
var close func()
midiOut, close = initMidi()
defer close()
// hit()

// if true {
// return
// }

var (
verbose *bool
printValues *bool
Expand All @@ -361,10 +392,49 @@ func main() {
flag.Var(&portMatches, "port", "Name or regex pattern matching one or more jack ports.")
flag.Parse()

visualizer := newVisualizer(*flagChannels, *flagOffset, *flagBuffer, *flagAmplifier, portMatches, *verbose, *printValues, *printChnIdx, *printNames)
err := visualizer.Start()
if err != nil {
panic(err)
v := newVisualizer(*flagChannels, *flagOffset, *flagBuffer, *flagAmplifier, portMatches, *verbose, *printValues, *printChnIdx, *printNames)
go v.Start()

interrupted := make(chan bool)

// signal handler
sigChan := make(chan os.Signal, 2)
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
go func() {
<-sigChan
fmt.Println("custom shutdown 2")
// v.shutdown()
interrupted <- true
}()

// buffer := int(v.client.GetBufferSize())
// v.additionalBuffer = v.calculateAdditionalBuffer(buffer)

<-interrupted

// err := visualizer.Start()
// if err != nil {
// panic(err)
// }
// printlne("Bye!")
}

var printfe = func(s string, toFormat ...interface{}) {
// if true {
// return
// }
fmt.Printf(s, toFormat)
}

var printe = func(s string) {
if true {
return
}
fmt.Println("Bye!")
fmt.Print(s)
}
var printlne = func(s string) {
// if true {
// return
// }
fmt.Println(s)
}
55 changes: 55 additions & 0 deletions midi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"encoding/json"
"fmt"

"gitlab.com/gomidi/midi"
_ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv" // autoregisters driver

mid "jack-peak-meter/midi"
)

func initMidi() (midi.Out, func()) {
midiIO := &mid.PortMidiIO{}
ms, err := mid.NewMidiSystem(midiIO)
must(err)

fmt.Println(ms.String())

return ms.GetOutputByName("IAC Driver Bus 1"), ms.Close
// return ms.GetOutputByName("Juno USB Midi "), ms.Close
}

var printf = fmt.Printf

func must(err error, strs ...string) {
if err != nil {
printf(err.Error())
if (len(strs)) > 0 {
printf(strs[0])
}
// panic(err.Error())
}
}

func assert(cond bool, strs ...string) {
if !cond {
printf("assertion failed")
s := ""
if (len(strs)) > 0 {
s = strs[0]
}

panic(s)
}
}

func logJSON(o interface{}) {
b, err := json.MarshalIndent(o, "", " ")
if err != nil {
printf("error marshaling json %s", err.Error())
}

printf("%T\n%s\n", o, string(b))
}
Loading