-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
164 lines (128 loc) · 4.32 KB
/
main.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
package main
import (
"fmt"
"github.com/HaBaLeS/synt-go-thic/engine"
"github.com/HaBaLeS/synt-go-thic/mpk"
"github.com/ebitengine/oto/v3"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
//_ "gitlab.com/gomidi/midi/v2/drivers/midicatdrv"
//_ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv"
"log"
"math"
"time"
)
var pos = 0.0
/*
27.5 -> A0
55 -> A1
110 -> A2
220 -> A3
440 -> A4
Base Frequ is
--> 27,5 *2^n
*/
var version string
var buildtime string
var deckBuild string
const samplerate float64 = 48000.0
const octaveBaseFreq = 110.0
var toneFrequIncrment float64 = math.Pow(2, 1.0/12.0)
type Game struct {
maxbuffer int //1chan * 48000/s * 16
player *oto.Player
midi *mpk.MPK3Mini
mixer *engine.Mixer
keyToChannelMap map[int]int
}
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("Key Press additional Gain -> %d", g.midi.KnobVal("K1")), 20, 100)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("Waveform Select K2 -> %d", g.midi.KnobVal("K2")), 20, 116)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf(">%s<", g.mixer.WaveFormName), 200, 116)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("# Harmonics -> %d", g.midi.KnobVal("K3")), 20, 132)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("K4 -> %d", g.midi.KnobVal("K4")), 20, 148+100)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("K5 -> %d", g.midi.KnobVal("K5")), 20, 164+100)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("K6 -> %d", g.midi.KnobVal("K6")), 20, 178+100)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("K7 -> %d", g.midi.KnobVal("K7")), 20, 192+100)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("K8 -> %d", g.midi.KnobVal("K8")), 20, 208+100)
/*for i, v := range g.midi.MidiKeys() {
if v != nil {
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("Piano Tone %s", v.Name), 200, 100+16*i)
}
}*/
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return outsideWidth, outsideHeight
}
func main() {
fmt.Println("synt-go-thic starting ....")
var bufTimeMS time.Duration = 5
bits := 16
channels := 1
op := &oto.NewContextOptions{}
// Usually 44100 or 48000. Other values might cause distortions in Oto
op.SampleRate = int(samplerate)
// Number of channels (aka locations) to play sounds from. Either 1 or 2.
// 1 is mono sound, and 2 is stereo (most speakers are stereo).
op.ChannelCount = channels
// Format of the source.
op.Format = oto.FormatSignedInt16LE
op.BufferSize = bufTimeMS * time.Millisecond
// Remember that you should **not** create more than one context
otoCtx, readyChan, err := oto.NewContext(op)
if err != nil {
panic("oto.NewContext failed: " + err.Error())
}
// It might take a bit for the hardware audio devices to be ready, so we wait on the channel.
<-readyChan
game := &Game{
maxbuffer: int(samplerate/1000.0) * int(bufTimeMS) * (bits / 8) * channels,
keyToChannelMap: make(map[int]int),
}
fmt.Printf("Creating Midi Device\n")
game.midi = mpk.NewMPK3Mini()
game.mixer = engine.NewMixer(10, game.midi)
fmt.Printf("Creating Audio Plyer\n")
game.player = otoCtx.NewPlayer(game.mixer)
game.player.SetBufferSize(game.maxbuffer * 2)
game.player.Play()
fmt.Printf("Global Buffer is %dms with a buffer size of %d (%d bits, %d channels)\n", bufTimeMS, game.maxbuffer, bits, channels)
ebiten.SetWindowSize(1280, 800)
ebiten.SetWindowTitle("Synth-GO-thic")
if deckBuild == "yes" {
ebiten.SetFullscreen(true)
}
if err := ebiten.RunGame(game); err != nil {
log.Fatal(err)
}
game.midi.Stop()
err = game.player.Close()
if err != nil {
panic("player.Close failed: " + err.Error())
}
}
func (g *Game) Update() error {
midiKeys := g.midi.MidiKeys()
for _, k := range midiKeys {
if k.EventType == mpk.EventPress {
for i := 0; i < g.mixer.MaxChannels; i++ {
c := g.mixer.Channel(i)
if c.Frequency == 0.0 {
g.keyToChannelMap[k.Idx] = i
bf := math.Pow(2, float64(k.Octave)) * 27.5 //frequ of A
frequ := bf * math.Pow(toneFrequIncrment, float64(k.Number-9))
c.Frequency = frequ
c.Velocity(k.Velocity)
break
}
}
} else if k.EventType == mpk.EventRelease {
cn := g.keyToChannelMap[k.Idx]
g.mixer.Channel(cn).Frequency = 0.0
delete(g.keyToChannelMap, k.Idx)
fmt.Printf("KM %v", g.keyToChannelMap)
}
}
g.midi.ClearEvents()
return nil
}