-
Notifications
You must be signed in to change notification settings - Fork 0
/
clicks.go
181 lines (144 loc) · 4.44 KB
/
clicks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
package kit
import (
"math"
"sync"
)
// Clicks is a time or duration value.
// NOTE: A Clicks value can be negative because
// it's sometimes relative to the starting time of a Phrase.
// XXX - possiblycould have a type to distinguish Clicks that are
// XXX - used as absolute time versus Clicks that are step numbers
type Clicks int64
var WholeNote = Clicks(96)
var HalfNote = Clicks(48)
var QuarterNote = Clicks(24)
var EighthNote = Clicks(12)
var SixteenthNote = Clicks(6)
var ThirtySecondNote = Clicks(3)
// MaxClicks is the high-possible value for Clicks
var MaxClicks = Clicks(math.MaxInt64)
// XXX - having Mutexes for all of these values
// is probably silly, should be simplified
var engineCurrentMilli int64
var engineCurrentMilliMutex sync.RWMutex
var engineCurrentMilliOffset int64
var engineCurrentMilliOffsetMutex sync.RWMutex
var engineCurrentClickOffset Clicks
var engineCurrentClickOffsetMutex sync.RWMutex
var engineClicksPerSecond Clicks
var engineClicksPerSecondMutex sync.RWMutex
var engineCurrentClick Clicks
var globaclCurrentClickMutex sync.RWMutex
var OneBeat Clicks
var OneBeatMutex sync.RWMutex
// CurrentMilli is the time from the start, in milliseconds
const defaultClicksPerSecond = Clicks(192)
const minClicksPerSecond = (defaultClicksPerSecond / 16)
const maxClicksPerSecond = (defaultClicksPerSecond * 16)
// var loopForever = 999999
// Bits for Events
const EventMidiInput = 0x01
const EventNoteOutput = 0x02
const EventCursor = 0x04
const EventAll = EventMidiInput | EventNoteOutput | EventCursor
type ClickEvent struct {
Click Clicks
Uptime float64
}
// InitializeClicksPerSecond initializes
func InitializeClicksPerSecond(clkpersec Clicks) {
// no locks needed here
engineClicksPerSecond = clkpersec
engineCurrentMilliOffset = 0
engineCurrentClickOffset = 0
OneBeat = Clicks(engineClicksPerSecond / 2) // i.e. 120bpm
}
// ChangeClicksPerSecond is what you use to change the tempo
func ChangeClicksPerSecond(factor float64) {
TempoFactor = factor
cpsf := float64(defaultClicksPerSecond)
clkpersec := Clicks(cpsf * factor)
if clkpersec < minClicksPerSecond {
clkpersec = minClicksPerSecond
}
if clkpersec > maxClicksPerSecond {
clkpersec = maxClicksPerSecond
}
SetCurrentMilliOffset(CurrentMilli())
SetCurrentClickOffset(CurrentClick())
SetClicksPerSecond(clkpersec)
OneBeat = Clicks(ClicksPerSecond() / 2)
}
// Seconds2Clicks converts a Time value (elapsed seconds) to Clicks
func Seconds2Clicks(tm float64) Clicks {
clickOffset := CurrentClickOffset()
cps := ClicksPerSecond()
milliOffset := CurrentMilliOffset()
cpsf := float64(cps)
var tmpclicks = Clicks(0.5 + float64(tm*1000-float64(milliOffset))*(cpsf/1000.0))
click := clickOffset + tmpclicks
return click
}
// Clicks2Seconds converts Clicks to Time (seconds), relative
func Clicks2Seconds(clk Clicks) float64 {
cps := engineClicksPerSecond
clkf := float64(clk)
return clkf / float64(cps)
}
// TempoFactor xxx
var TempoFactor = float64(1.0)
// CurrentMilli
func CurrentMilli() int64 {
engineCurrentMilliMutex.RLock()
defer engineCurrentMilliMutex.RUnlock()
return engineCurrentMilli
}
func SetCurrentMilli(milli int64) {
engineCurrentMilliMutex.Lock()
engineCurrentMilli = milli
engineCurrentMilliMutex.Unlock()
}
// CurrentMilliOffset
func CurrentMilliOffset() int64 {
engineCurrentMilliOffsetMutex.RLock()
defer engineCurrentMilliOffsetMutex.RUnlock()
return engineCurrentMilliOffset
}
func SetCurrentMilliOffset(milli int64) {
engineCurrentMilliOffsetMutex.Lock()
engineCurrentMilliOffset = milli
engineCurrentMilliOffsetMutex.Unlock()
}
// ClicksPerSecond
func ClicksPerSecond() Clicks {
engineClicksPerSecondMutex.RLock()
defer engineClicksPerSecondMutex.RUnlock()
return Clicks(engineClicksPerSecond)
}
func SetClicksPerSecond(cps Clicks) {
engineClicksPerSecondMutex.Lock()
engineClicksPerSecond = cps
engineClicksPerSecondMutex.Unlock()
}
// CurrentClick
func CurrentClick() Clicks {
globaclCurrentClickMutex.RLock()
defer globaclCurrentClickMutex.RUnlock()
return engineCurrentClick
}
func SetCurrentClick(click Clicks) {
globaclCurrentClickMutex.Lock()
engineCurrentClick = click
globaclCurrentClickMutex.Unlock()
}
// CurrentClickOffset
func CurrentClickOffset() Clicks {
engineCurrentClickOffsetMutex.RLock()
defer engineCurrentClickOffsetMutex.RUnlock()
return engineCurrentClickOffset
}
func SetCurrentClickOffset(click Clicks) {
engineCurrentClickOffsetMutex.Lock()
engineCurrentClickOffset = click
engineCurrentClickOffsetMutex.Unlock()
}