mirror of
https://github.com/vsariola/sointu.git
synced 2026-02-08 00:30:18 -05:00
drafting
This commit is contained in:
parent
fd5e2c3bb8
commit
b328cc3a07
@ -38,6 +38,9 @@ type SongPanel struct {
|
||||
Step *NumericUpDownState
|
||||
SongLength *NumericUpDownState
|
||||
|
||||
List *layout.List
|
||||
ScrollBar *ScrollBar
|
||||
|
||||
Scope *OscilloscopeState
|
||||
|
||||
SpectrumState *SpectrumState
|
||||
@ -68,6 +71,9 @@ func NewSongPanel(tr *Tracker) *SongPanel {
|
||||
CPUExpander: &Expander{},
|
||||
SpectrumExpander: &Expander{},
|
||||
|
||||
List: &layout.List{Axis: layout.Vertical},
|
||||
ScrollBar: &ScrollBar{Axis: layout.Vertical},
|
||||
|
||||
SpectrumState: NewSpectrumState(),
|
||||
}
|
||||
return ret
|
||||
@ -158,8 +164,9 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
|
||||
synthBtn := Btn(tr.Theme, &tr.Theme.Button.Text, t.SynthBtn, tr.Model.SyntherName(), "")
|
||||
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
layout.Rigid(func(gtx C) D {
|
||||
listItem := func(gtx C, index int) D {
|
||||
switch index {
|
||||
case 0:
|
||||
return t.SongSettingsExpander.Layout(gtx, tr.Theme, "Song",
|
||||
func(gtx C) D {
|
||||
return Label(tr.Theme, &tr.Theme.SongPanel.RowHeader, strconv.Itoa(tr.BPM().Value())+" BPM").Layout(gtx)
|
||||
@ -188,8 +195,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
}),
|
||||
)
|
||||
})
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
case 1:
|
||||
return t.CPUExpander.Layout(gtx, tr.Theme, "CPU", cpuSmallLabel,
|
||||
func(gtx C) D {
|
||||
return layout.Flex{Axis: layout.Vertical, Alignment: layout.End}.Layout(gtx,
|
||||
@ -198,8 +204,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
)
|
||||
},
|
||||
)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
case 2:
|
||||
return t.LoudnessExpander.Layout(gtx, tr.Theme, "Loudness",
|
||||
func(gtx C) D {
|
||||
loudness := tr.Model.DetectorResult().Loudness[tracker.LoudnessShortTerm]
|
||||
@ -229,8 +234,7 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
)
|
||||
},
|
||||
)
|
||||
}),
|
||||
layout.Rigid(func(gtx C) D {
|
||||
case 3:
|
||||
return t.PeakExpander.Layout(gtx, tr.Theme, "Peaks",
|
||||
func(gtx C) D {
|
||||
maxPeak := max(tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][0], tr.Model.DetectorResult().Peaks[tracker.PeakShortTerm][1])
|
||||
@ -258,16 +262,24 @@ func (t *SongPanel) layoutSongOptions(gtx C) D {
|
||||
)
|
||||
},
|
||||
)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
case 4:
|
||||
gtx.Constraints.Max.Y = gtx.Dp(300)
|
||||
scope := Scope(tr.Theme, tr.Model.SignalAnalyzer(), t.Scope)
|
||||
return t.ScopeExpander.Layout(gtx, tr.Theme, "Oscilloscope", func(gtx C) D { return D{} }, scope.Layout)
|
||||
}),
|
||||
layout.Flexed(1, func(gtx C) D {
|
||||
case 5:
|
||||
gtx.Constraints.Max.Y = gtx.Dp(300)
|
||||
return t.SpectrumExpander.Layout(gtx, tr.Theme, "Spectrum", func(gtx C) D { return D{} }, t.SpectrumState.Layout)
|
||||
}),
|
||||
layout.Rigid(Label(tr.Theme, &tr.Theme.SongPanel.Version, version.VersionOrHash).Layout),
|
||||
)
|
||||
case 6:
|
||||
return Label(tr.Theme, &tr.Theme.SongPanel.Version, version.VersionOrHash).Layout(gtx)
|
||||
default:
|
||||
return D{}
|
||||
}
|
||||
}
|
||||
gtx.Constraints.Min = gtx.Constraints.Max
|
||||
dims := t.List.Layout(gtx, 7, listItem)
|
||||
t.ScrollBar.Layout(gtx, &tr.Theme.ScrollBar, 7, &t.List.Position)
|
||||
tr.SpecAnEnabled().SetValue(t.SpectrumExpander.Expanded)
|
||||
return dims
|
||||
}
|
||||
|
||||
func dbLabel(th *Theme, value tracker.Decibel) LabelWidget {
|
||||
|
||||
@ -48,7 +48,7 @@ func (s *SpectrumState) Layout(gtx C) D {
|
||||
}
|
||||
|
||||
resolution := NumUpDown(t.Model.SpecAnResolution(), t.Theme, s.resolutionNumber, "Resolution")
|
||||
chnModeBtn := Btn(t.Theme, &t.Theme.Button.Filled, s.chnModeBtn, chnModeTxt, "Channel mode")
|
||||
chnModeBtn := Btn(t.Theme, &t.Theme.Button.Text, s.chnModeBtn, chnModeTxt, "Channel mode")
|
||||
speed := NumUpDown(t.Model.SpecAnSpeed(), t.Theme, s.speed, "Speed")
|
||||
|
||||
numchns := 0
|
||||
|
||||
@ -79,6 +79,7 @@ type (
|
||||
oversampling bool
|
||||
|
||||
specAnSettings SpecAnSettings
|
||||
specAnEnabled bool
|
||||
|
||||
alerts []Alert
|
||||
dialog Dialog
|
||||
@ -402,14 +403,16 @@ func (m *Model) ProcessMsg(msg MsgToModel) {
|
||||
case *sointu.AudioBuffer:
|
||||
m.signalAnalyzer.ProcessAudioBuffer(e)
|
||||
// chain the messages: when we have a new audio buffer, send them to the detector and the spectrum analyzer
|
||||
clone := m.broker.GetAudioBuffer()
|
||||
*clone = append(*clone, *e...)
|
||||
if m.specAnEnabled { // send buffers to spectrum analyzer only if it's enabled
|
||||
clone := m.broker.GetAudioBuffer()
|
||||
*clone = append(*clone, *e...)
|
||||
if !TrySend(m.broker.ToSpecAn, MsgToSpecAn{Data: clone}) {
|
||||
m.broker.PutAudioBuffer(clone)
|
||||
}
|
||||
}
|
||||
if !TrySend(m.broker.ToDetector, MsgToDetector{Data: e}) {
|
||||
m.broker.PutAudioBuffer(e)
|
||||
}
|
||||
if !TrySend(m.broker.ToSpecAn, MsgToSpecAn{Data: clone}) {
|
||||
m.broker.PutAudioBuffer(clone)
|
||||
}
|
||||
case *Spectrum:
|
||||
m.broker.PutSpectrum(m.spectrum)
|
||||
m.spectrum = e
|
||||
|
||||
@ -38,6 +38,8 @@ type (
|
||||
b0, b1, b2 float32
|
||||
a0, a1, a2 float32
|
||||
}
|
||||
|
||||
SpecAnEnabled Model
|
||||
)
|
||||
|
||||
const (
|
||||
@ -56,6 +58,8 @@ const (
|
||||
NumSpecChnModes
|
||||
)
|
||||
|
||||
func (m *Model) SpecAnEnabled() Bool { return MakeEnabledBool((*simpleBool)(&m.specAnEnabled)) }
|
||||
|
||||
func NewSpecAnalyzer(broker *Broker) *SpecAnalyzer {
|
||||
ret := &SpecAnalyzer{broker: broker}
|
||||
ret.init(SpecAnSettings{})
|
||||
@ -74,25 +78,29 @@ func (m *Model) BiquadCoeffs() (coeffs BiquadCoeffs, ok bool) {
|
||||
f := float32(p["frequency"]) / 128
|
||||
f *= f
|
||||
r := float32(p["resonance"]) / 128
|
||||
// in state-space, the filter has the form:
|
||||
// s(n+1) = A*s(n)+B*u, where A = [1 f;-f 1-f*r-f*f] and B = [0;f]
|
||||
// y(n) = C*s(n)+D*u, where
|
||||
// C_low = [1 0]*z, C_band = [0 1]*z, C_high = [-1 -f-r], D_high = [1]
|
||||
// The equations for the filter are:
|
||||
// s1[n+1] = s1[n] + f*s2[n]
|
||||
// h = u - s1[n+1] - r*s2[n]
|
||||
// s2[n+1] = s2[n] + f*h = s2[n] + f*(u-s1[n]-f*s2[n]-r*s2[n]) = - f*s1[n]+(1-f*r-f*f)*s2[n] + f*u
|
||||
// y_low[n] = s1[n+1], y_band[n] = s2[n+1], y_high[n] = -s1[n+1]-r*s2[n]+u
|
||||
// This gives state space representation
|
||||
// s(n+1) = A*s(n)+B*u, where A = [1 f;-f 1-f*r-f*f] and B = [0;f]
|
||||
// y(n) = C*s(n)+D*u, where
|
||||
// C_low = [z 0], C_band = [0 z], C_high = [-z -r], D_high = [1] (note we use those z:s in C to account for those 1 sample time shifts)
|
||||
// The transfer function is then H(z) = C*(zI-A)^-1*B + D
|
||||
// z*I-A = [z-1 -f; f z+f*r+f*f-1]
|
||||
// Invert it:
|
||||
// (z*I-A)^-1 = 1/det * [z+f*r+f*f-1 f; -f z-1], where det = (z-1)*(z+f*r+f*f-1)+f^2 = z*z+z*f*r+z*f*f-z-z-f*r-f*f+1+f^2 = z*z + z*(f*r+f*f-2)-f*r+1
|
||||
// (z*I-A)^-1*B = 1/det * f * [f; z-1]
|
||||
// Low: z * [1,0] * f * [f;z-1] / det = f*f*z / det
|
||||
// Band: z * [0,1] * f * [f;z-1] / det = (f*z^2-f*z) / det
|
||||
// High: [-1,-f-r] * f * [f;z-1] / det + 1 = ((-f*f-r*f)*z+r*f)/det + 1 = ((-f*f-r*f)*z+r*f+det)/det = (z^2-2*z+1)/det
|
||||
// z*I-A = [z-1 -f; f z+f*r+f*f-1]
|
||||
// Calculate (zI-A)^-1*B:
|
||||
// (z*I-A)^-1*B = 1/det * [z+f*r+f*f-1 f; -f z-1] * [0;f] = 1/det * f * [f; z-1], where
|
||||
// det = (z+f*r+f*f-1)*(z-1)+f^2 = z*z+z*f*r+z*f*f-z-z-f*r-f*f+1+f^2 = z*z + (r*f+f*f-2)*z + 1-f*r = a0*z^2 + a1*z + a2
|
||||
// Low: [z 0]*f*[f;z-1] / det = f*f*z / det = b1 * z / det
|
||||
// Band: [0 z]*f*[f;z-1] / det = (f*z^2-f*z) / det = (b0*z^2 + b1*z) / det
|
||||
// High: [-z -r]*f*[f;z-1] / det + 1 = ((-f*f-r*f)*z+r*f)/det + 1 = ((-f*f-r*f)*z+r*f+det)/det = (z^2-2*z+1)/det = (b0*z^2 + b1*z + b2)/det
|
||||
// Negative versions have only b coefficients negated
|
||||
var a0 float32 = 1
|
||||
var a1 float32 = r*f + f*f - 2
|
||||
var a2 float32 = 1 - f*r
|
||||
var b0, b1, b2 float32
|
||||
if p["lowpass"] == 1 {
|
||||
b1 = f * f
|
||||
}
|
||||
b1 += f * f * float32(p["lowpass"])
|
||||
b0 += f * float32(p["bandpass"])
|
||||
b1 -= f * float32(p["bandpass"])
|
||||
b0 += float32(p["highpass"])
|
||||
|
||||
Reference in New Issue
Block a user