Skip to content
This repository was archived by the owner on Jul 21, 2022. It is now read-only.

Commit a1f5b2e

Browse files
author
Jason Crawford
committed
Initial import
1 parent 8938d07 commit a1f5b2e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+2310
-0
lines changed

ampmodulator.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package voice
2+
3+
import (
4+
"github.com/gotracker/gomixing/volume"
5+
)
6+
7+
// AmpModulator is the instrument volume (amplitude) control interface
8+
type AmpModulator interface {
9+
SetVolume(vol volume.Volume)
10+
GetVolume() volume.Volume
11+
GetFinalVolume() volume.Volume
12+
}

autovibrato.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package voice
2+
3+
import (
4+
"github.com/gotracker/voice/oscillator"
5+
)
6+
7+
// AutoVibrato is the setting and memory for the auto-vibrato system
8+
type AutoVibrato struct {
9+
Enabled bool
10+
Sweep int
11+
WaveformSelection uint8
12+
Depth float32
13+
Rate int
14+
Factory func() oscillator.Oscillator
15+
}
16+
17+
// Generate creates an AutoVibrato waveform oscillator and configures it with the inital values
18+
func (a *AutoVibrato) Generate() oscillator.Oscillator {
19+
if a.Factory == nil {
20+
return nil
21+
}
22+
o := a.Factory()
23+
o.SetWaveform(oscillator.WaveTableSelect(a.WaveformSelection))
24+
return o
25+
}

callback.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package voice
2+
3+
// Callback is a callback function for performing some sort of action at a later time
4+
type Callback func(v Voice)

component/envelope.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package component
2+
3+
// Envelope is an envelope component interface
4+
type Envelope interface {
5+
//Reset(env *envelope.Envelope)
6+
SetEnabled(enabled bool)
7+
IsEnabled() bool
8+
Advance(keyOn bool, prevKeyOn bool)
9+
}

component/envelope_filter.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package component
2+
3+
import (
4+
"github.com/gotracker/voice"
5+
"github.com/gotracker/voice/envelope"
6+
)
7+
8+
// FilterEnvelope is a filter frequency cutoff modulation envelope
9+
type FilterEnvelope struct {
10+
enabled bool
11+
state envelope.State
12+
value float32
13+
keyOn bool
14+
prevKeyOn bool
15+
}
16+
17+
// Reset resets the state to defaults based on the envelope provided
18+
func (e *FilterEnvelope) Reset(env *envelope.Envelope) {
19+
e.state.Reset(env)
20+
e.keyOn = false
21+
e.prevKeyOn = false
22+
e.update()
23+
}
24+
25+
// SetEnabled sets the enabled flag for the envelope
26+
func (e *FilterEnvelope) SetEnabled(enabled bool) {
27+
e.enabled = enabled
28+
}
29+
30+
// IsEnabled returns the enabled flag for the envelope
31+
func (e *FilterEnvelope) IsEnabled() bool {
32+
return e.enabled
33+
}
34+
35+
// GetCurrentValue returns the current cached envelope value
36+
func (e *FilterEnvelope) GetCurrentValue() float32 {
37+
return e.value
38+
}
39+
40+
// SetEnvelopePosition sets the current position in the envelope
41+
func (e *FilterEnvelope) SetEnvelopePosition(pos int) voice.Callback {
42+
keyOn := e.keyOn
43+
prevKeyOn := e.prevKeyOn
44+
env := e.state.Envelope()
45+
e.state.Reset(env)
46+
// TODO: this is gross, but currently the most optimal way to find the correct position
47+
for i := 0; i < pos; i++ {
48+
if doneCB := e.Advance(keyOn, prevKeyOn); doneCB != nil {
49+
return doneCB
50+
}
51+
}
52+
return nil
53+
}
54+
55+
// Advance advances the envelope state 1 tick and calculates the current envelope value
56+
func (e *FilterEnvelope) Advance(keyOn bool, prevKeyOn bool) voice.Callback {
57+
e.keyOn = keyOn
58+
e.prevKeyOn = prevKeyOn
59+
var doneCB voice.Callback
60+
if done := e.state.Advance(e.keyOn, e.prevKeyOn); done {
61+
doneCB = e.state.Envelope().OnFinished
62+
}
63+
e.update()
64+
return doneCB
65+
}
66+
67+
func (e *FilterEnvelope) update() {
68+
cur, next, t := e.state.GetCurrentValue(e.keyOn)
69+
70+
y0 := float32(0)
71+
if cur != nil {
72+
cur.Value(&y0)
73+
}
74+
75+
y1 := float32(0)
76+
if next != nil {
77+
next.Value(&y1)
78+
}
79+
80+
e.value = y0 + t*(y1-y0)
81+
e.value /= 256
82+
}

component/envelope_pan.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package component
2+
3+
import (
4+
"github.com/gotracker/gomixing/panning"
5+
6+
"github.com/gotracker/voice"
7+
"github.com/gotracker/voice/envelope"
8+
)
9+
10+
// PanEnvelope is a spatial modulation envelope
11+
type PanEnvelope struct {
12+
enabled bool
13+
state envelope.State
14+
pan panning.Position
15+
keyOn bool
16+
prevKeyOn bool
17+
}
18+
19+
// Reset resets the state to defaults based on the envelope provided
20+
func (e *PanEnvelope) Reset(env *envelope.Envelope) {
21+
e.state.Reset(env)
22+
e.keyOn = false
23+
e.prevKeyOn = false
24+
e.update()
25+
}
26+
27+
// SetEnabled sets the enabled flag for the envelope
28+
func (e *PanEnvelope) SetEnabled(enabled bool) {
29+
e.enabled = enabled
30+
}
31+
32+
// IsEnabled returns the enabled flag for the envelope
33+
func (e *PanEnvelope) IsEnabled() bool {
34+
return e.enabled
35+
}
36+
37+
// GetCurrentValue returns the current cached envelope value
38+
func (e *PanEnvelope) GetCurrentValue() panning.Position {
39+
return e.pan
40+
}
41+
42+
// SetEnvelopePosition sets the current position in the envelope
43+
func (e *PanEnvelope) SetEnvelopePosition(pos int) voice.Callback {
44+
keyOn := e.keyOn
45+
prevKeyOn := e.prevKeyOn
46+
env := e.state.Envelope()
47+
e.state.Reset(env)
48+
// TODO: this is gross, but currently the most optimal way to find the correct position
49+
for i := 0; i < pos; i++ {
50+
if doneCB := e.Advance(keyOn, prevKeyOn); doneCB != nil {
51+
return doneCB
52+
}
53+
}
54+
return nil
55+
}
56+
57+
// Advance advances the envelope state 1 tick and calculates the current envelope value
58+
func (e *PanEnvelope) Advance(keyOn bool, prevKeyOn bool) voice.Callback {
59+
e.keyOn = keyOn
60+
e.prevKeyOn = prevKeyOn
61+
var doneCB voice.Callback
62+
if done := e.state.Advance(e.keyOn, e.prevKeyOn); done {
63+
doneCB = e.state.Envelope().OnFinished
64+
}
65+
e.update()
66+
return doneCB
67+
}
68+
69+
func (e *PanEnvelope) update() {
70+
cur, next, t := e.state.GetCurrentValue(e.keyOn)
71+
72+
y0 := panning.CenterAhead
73+
if cur != nil {
74+
cur.Value(&y0)
75+
}
76+
77+
y1 := panning.CenterAhead
78+
if next != nil {
79+
next.Value(&y1)
80+
}
81+
82+
// TODO: perform an angular interpolation instead of a linear one.
83+
e.pan.Angle = y0.Angle + t*(y1.Angle-y0.Angle)
84+
e.pan.Distance = y0.Distance + t*(y1.Distance-y0.Distance)
85+
}

component/envelope_pitch.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package component
2+
3+
import (
4+
"github.com/gotracker/voice"
5+
"github.com/gotracker/voice/envelope"
6+
"github.com/gotracker/voice/period"
7+
)
8+
9+
// PitchEnvelope is an frequency modulation envelope
10+
type PitchEnvelope struct {
11+
enabled bool
12+
state envelope.State
13+
delta period.Delta
14+
keyOn bool
15+
prevKeyOn bool
16+
}
17+
18+
// Reset resets the state to defaults based on the envelope provided
19+
func (e *PitchEnvelope) Reset(env *envelope.Envelope) {
20+
e.state.Reset(env)
21+
e.keyOn = false
22+
e.prevKeyOn = false
23+
e.update()
24+
}
25+
26+
// SetEnabled sets the enabled flag for the envelope
27+
func (e *PitchEnvelope) SetEnabled(enabled bool) {
28+
e.enabled = enabled
29+
}
30+
31+
// IsEnabled returns the enabled flag for the envelope
32+
func (e *PitchEnvelope) IsEnabled() bool {
33+
return e.enabled
34+
}
35+
36+
// GetCurrentValue returns the current cached envelope value
37+
func (e *PitchEnvelope) GetCurrentValue() period.Delta {
38+
return e.delta
39+
}
40+
41+
// SetEnvelopePosition sets the current position in the envelope
42+
func (e *PitchEnvelope) SetEnvelopePosition(pos int) voice.Callback {
43+
keyOn := e.keyOn
44+
prevKeyOn := e.prevKeyOn
45+
env := e.state.Envelope()
46+
e.state.Reset(env)
47+
// TODO: this is gross, but currently the most optimal way to find the correct position
48+
for i := 0; i < pos; i++ {
49+
if doneCB := e.Advance(keyOn, prevKeyOn); doneCB != nil {
50+
return doneCB
51+
}
52+
}
53+
return nil
54+
}
55+
56+
// Advance advances the envelope state 1 tick and calculates the current envelope value
57+
func (e *PitchEnvelope) Advance(keyOn bool, prevKeyOn bool) voice.Callback {
58+
e.keyOn = keyOn
59+
e.prevKeyOn = prevKeyOn
60+
var doneCB voice.Callback
61+
if done := e.state.Advance(e.keyOn, e.prevKeyOn); done {
62+
doneCB = e.state.Envelope().OnFinished
63+
}
64+
e.update()
65+
return doneCB
66+
}
67+
68+
func (e *PitchEnvelope) update() {
69+
cur, next, t := e.state.GetCurrentValue(e.keyOn)
70+
71+
y0 := float32(0)
72+
if cur != nil {
73+
cur.Value(&y0)
74+
}
75+
76+
y1 := float32(0)
77+
if next != nil {
78+
next.Value(&y1)
79+
}
80+
81+
val := y0 + t*(y1-y0)
82+
e.delta = period.Delta(-val)
83+
}

component/envelope_volume.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package component
2+
3+
import (
4+
"github.com/gotracker/gomixing/volume"
5+
6+
"github.com/gotracker/voice"
7+
"github.com/gotracker/voice/envelope"
8+
)
9+
10+
// VolumeEnvelope is an amplitude modulation envelope
11+
type VolumeEnvelope struct {
12+
enabled bool
13+
state envelope.State
14+
vol volume.Volume
15+
keyOn bool
16+
prevKeyOn bool
17+
}
18+
19+
// Reset resets the state to defaults based on the envelope provided
20+
func (e *VolumeEnvelope) Reset(env *envelope.Envelope) {
21+
e.state.Reset(env)
22+
e.keyOn = false
23+
e.prevKeyOn = false
24+
e.update()
25+
}
26+
27+
// SetEnabled sets the enabled flag for the envelope
28+
func (e *VolumeEnvelope) SetEnabled(enabled bool) {
29+
e.enabled = enabled
30+
}
31+
32+
// IsEnabled returns the enabled flag for the envelope
33+
func (e *VolumeEnvelope) IsEnabled() bool {
34+
return e.enabled
35+
}
36+
37+
// GetCurrentValue returns the current cached envelope value
38+
func (e *VolumeEnvelope) GetCurrentValue() volume.Volume {
39+
return e.vol
40+
}
41+
42+
// SetEnvelopePosition sets the current position in the envelope
43+
func (e *VolumeEnvelope) SetEnvelopePosition(pos int) voice.Callback {
44+
keyOn := e.keyOn
45+
prevKeyOn := e.prevKeyOn
46+
env := e.state.Envelope()
47+
e.state.Reset(env)
48+
// TODO: this is gross, but currently the most optimal way to find the correct position
49+
for i := 0; i < pos; i++ {
50+
if doneCB := e.Advance(keyOn, prevKeyOn); doneCB != nil {
51+
return doneCB
52+
}
53+
}
54+
return nil
55+
}
56+
57+
// Advance advances the envelope state 1 tick and calculates the current envelope value
58+
func (e *VolumeEnvelope) Advance(keyOn bool, prevKeyOn bool) voice.Callback {
59+
e.keyOn = keyOn
60+
e.prevKeyOn = prevKeyOn
61+
var doneCB voice.Callback
62+
if done := e.state.Advance(e.keyOn, e.prevKeyOn); done {
63+
doneCB = e.state.Envelope().OnFinished
64+
}
65+
e.update()
66+
return doneCB
67+
}
68+
69+
func (e *VolumeEnvelope) update() {
70+
cur, next, t := e.state.GetCurrentValue(e.keyOn)
71+
72+
y0 := volume.Volume(0)
73+
if cur != nil {
74+
cur.Value(&y0)
75+
}
76+
77+
y1 := volume.Volume(0)
78+
if next != nil {
79+
next.Value(&y1)
80+
}
81+
82+
e.vol = y0 + volume.Volume(t)*(y1-y0)
83+
}

0 commit comments

Comments
 (0)