machine/usb: move MIDI under usb/adc (Audio Device Class) package

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram
2023-04-28 18:09:54 +02:00
committed by Ron Evans
parent d28b58e4dd
commit c70daa2497
9 changed files with 13 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
// package adc is for USB Audio Device Class devices.
package adc
+52
View File
@@ -0,0 +1,52 @@
package midi
import (
"runtime/volatile"
)
const bufferSize = 128
// RingBuffer is ring buffer implementation inspired by post at
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
type RingBuffer struct {
rxbuffer [bufferSize][4]byte
head volatile.Register8
tail volatile.Register8
}
// NewRingBuffer returns a new ring buffer.
func NewRingBuffer() *RingBuffer {
return &RingBuffer{}
}
// Used returns how many bytes in buffer have been used.
func (rb *RingBuffer) Used() uint8 {
return uint8(rb.head.Get() - rb.tail.Get())
}
// Put stores a byte in the buffer. If the buffer is already
// full, the method will return false.
func (rb *RingBuffer) Put(val []byte) bool {
if rb.Used() != bufferSize {
rb.head.Set(rb.head.Get() + 1)
copy(rb.rxbuffer[rb.head.Get()%bufferSize][:], val)
return true
}
return false
}
// Get returns a byte from the buffer. If the buffer is empty,
// the method will return a false as the second value.
func (rb *RingBuffer) Get() ([]byte, bool) {
if rb.Used() != 0 {
rb.tail.Set(rb.tail.Get() + 1)
return rb.rxbuffer[rb.tail.Get()%bufferSize][:], true
}
return nil, false
}
// Clear resets the head and tail pointer to zero.
func (rb *RingBuffer) Clear() {
rb.head.Set(0)
rb.tail.Set(0)
}
+19
View File
@@ -0,0 +1,19 @@
package midi
// NoteOn sends a note on message.
func (m *midi) NoteOn(cable, channel uint8, note Note, velocity uint8) {
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0x9, 0x90|(channel&0xf), byte(note)&0x7f, velocity&0x7f
m.Write(m.msg[:])
}
// NoteOff sends a note off message.
func (m *midi) NoteOff(cable, channel uint8, note Note, velocity uint8) {
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0x8, 0x80|(channel&0xf), byte(note)&0x7f, velocity&0x7f
m.Write(m.msg[:])
}
// SendCC sends a continuous controller message.
func (m *midi) SendCC(cable, channel, control, value uint8) {
m.msg[0], m.msg[1], m.msg[2], m.msg[3] = (cable&0xf<<4)|0xB, 0xB0|(channel&0xf), control&0x7f, value&0x7f
m.Write(m.msg[:])
}
+89
View File
@@ -0,0 +1,89 @@
package midi
import (
"machine"
"machine/usb"
)
const (
midiEndpointOut = usb.MIDI_ENDPOINT_OUT // from PC
midiEndpointIn = usb.MIDI_ENDPOINT_IN // to PC
)
var Midi *midi
type midi struct {
msg [4]byte
buf *RingBuffer
rxHandler func([]byte)
waitTxc bool
}
func init() {
if Midi == nil {
Midi = newMidi()
}
}
// New returns the USB MIDI port.
// Deprecated, better to just use Port()
func New() *midi {
return Port()
}
// Port returns the USB midi port.
func Port() *midi {
return Midi
}
func newMidi() *midi {
m := &midi{
buf: NewRingBuffer(),
}
machine.EnableMIDI(m.Handler, m.RxHandler, nil)
return m
}
func (m *midi) SetHandler(rxHandler func([]byte)) {
m.rxHandler = rxHandler
}
func (m *midi) Write(b []byte) (n int, err error) {
i := 0
for i = 0; i < len(b); i += 4 {
m.tx(b[i : i+4])
}
return i, nil
}
// sendUSBPacket sends a MIDIPacket.
func (m *midi) sendUSBPacket(b []byte) {
machine.SendUSBInPacket(midiEndpointIn, b)
}
// from BulkIn
func (m *midi) Handler() {
m.waitTxc = false
if b, ok := m.buf.Get(); ok {
m.waitTxc = true
m.sendUSBPacket(b)
}
}
func (m *midi) tx(b []byte) {
if machine.USBDev.InitEndpointComplete {
if m.waitTxc {
m.buf.Put(b)
} else {
m.waitTxc = true
m.sendUSBPacket(b)
}
}
}
// from BulkOut
func (m *midi) RxHandler(b []byte) {
if m.rxHandler != nil {
m.rxHandler(b)
}
}
+108
View File
@@ -0,0 +1,108 @@
package midi
// Note represents a MIDI note number. For example, Note(69) is A4 or 440Hz.
type Note uint8
// Define all the notes in a format similar to the Tone library in the Arduino
// IDE.
const (
A0 Note = iota + 21 // 27.5Hz
AS0
B0
C1
CS1
D1
DS1
E1
F1
FS1
G1
GS1
A1 // 55Hz
AS1
B1
C2
CS2
D2
DS2
E2
F2
FS2
G2
GS2
A2 // 110Hz
AS2
B2
C3
CS3
D3
DS3
E3
F3
FS3
G3
GS3
A3 // 220Hz
AS3
B3
C4
CS4
D4
DS4
E4
F4
FS4
G4
GS4
A4 // 440Hz
AS4
B4
C5
CS5
D5
DS5
E5
F5
FS5
G5
GS5
A5 // 880Hz
AS5
B5
C6
CS6
D6
DS6
E6
F6
FS6
G6
GS6
A6 // 1760Hz
AS6
B6
C7
CS7
D7
DS7
E7
F7
FS7
G7
GS7
A7 // 3520Hz
AS7
B7
C8
CS8
D8
DS8
E8
F8
FS8
G8
GS8
A8 // 7040Hz
AS8
B8
)