Make MIDI transpose example functional
Signed-off-by: Christopher Arndt <chris@chrisarndt.de>
This commit is contained in:
parent
ba6aaa22ab
commit
9bb9321dcb
|
@ -1,6 +1,8 @@
|
||||||
## A simple MIDI event processor LV2 plugin
|
## A simple MIDI transpose LV2 plugin
|
||||||
|
|
||||||
import std/[math, strformat, strutils]
|
import std/math
|
||||||
|
#import std/strformat
|
||||||
|
#import std/strutils
|
||||||
import nymph/[atom, core, midi, util, urid]
|
import nymph/[atom, core, midi, util, urid]
|
||||||
import nymph/atom/util
|
import nymph/atom/util
|
||||||
|
|
||||||
|
@ -18,27 +20,17 @@ type
|
||||||
midi_urid: Urid
|
midi_urid: Urid
|
||||||
|
|
||||||
|
|
||||||
proc printFeatures(features: ptr UncheckedArray[ptr Lv2Feature]) =
|
|
||||||
if features != nil:
|
|
||||||
var i = 0
|
|
||||||
while true:
|
|
||||||
let feature = features[i]
|
|
||||||
if feature == nil:
|
|
||||||
break
|
|
||||||
echo &"URI: {feature[].uri}"
|
|
||||||
echo &"Data: {cast[int](feature[].data)}"
|
|
||||||
inc i
|
|
||||||
|
|
||||||
|
|
||||||
proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble;
|
||||||
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
|
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
|
||||||
Lv2Handle {.cdecl.} =
|
Lv2Handle {.cdecl.} =
|
||||||
printFeatures(features)
|
|
||||||
let amp: ptr MidiTransposePlugin = createShared(MidiTransposePlugin)
|
let amp: ptr MidiTransposePlugin = createShared(MidiTransposePlugin)
|
||||||
amp.map = cast[ptr UridMap](lv2FeaturesData(features, lv2UridMap))
|
amp.map = cast[ptr UridMap](lv2FeaturesData(features, lv2UridMap))
|
||||||
assert amp.map != nil
|
|
||||||
|
if amp.map == nil:
|
||||||
|
return nil
|
||||||
|
|
||||||
amp.midi_urid = amp.map[].map(amp.map[].handle, lv2MidiMidiEvent)
|
amp.midi_urid = amp.map[].map(amp.map[].handle, lv2MidiMidiEvent)
|
||||||
echo &"{lv2MidiMidiEvent} = {amp.midi_urid.int}"
|
|
||||||
return cast[Lv2Handle](amp)
|
return cast[Lv2Handle](amp)
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,18 +45,33 @@ proc connectPort(instance: Lv2Handle; port: cuint;
|
||||||
of PluginPort.Transposition:
|
of PluginPort.Transposition:
|
||||||
amp.transposition = cast[ptr cfloat](dataLocation)
|
amp.transposition = cast[ptr cfloat](dataLocation)
|
||||||
|
|
||||||
|
|
||||||
proc activate(instance: Lv2Handle) {.cdecl.} =
|
proc activate(instance: Lv2Handle) {.cdecl.} =
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
|
||||||
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
|
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
|
||||||
let amp = cast[ptr MidiTransposePlugin](instance)
|
let amp = cast[ptr MidiTransposePlugin](instance)
|
||||||
|
let outCapacity = amp.output.atom.size
|
||||||
|
atomSequenceClear(amp.output)
|
||||||
|
amp.output.atom.type = amp.input.atom.type
|
||||||
|
|
||||||
if amp.input.atom.size > 8:
|
if amp.input.atom.size > 8:
|
||||||
|
#echo &"Event sequence size: {amp.input.atom.size}"
|
||||||
|
|
||||||
for ev in items(amp.input):
|
for ev in items(amp.input):
|
||||||
if Urid(ev.body.`type`) == amp.midi_urid:
|
if Urid(ev.body.`type`) == amp.midi_urid:
|
||||||
# TODO
|
var msg = cast[ptr UncheckedArray[uint8]](atomContents(AtomEvent, ev))
|
||||||
var msg = cast[ptr UncheckedArray[uint8]](ev.body.addr + 1)
|
#echo &"0x{toHex(msg[0], 2)} 0x{toHex(msg[1], 2)} 0x{toHex(msg[2], 2)}"
|
||||||
echo &"0x{toHex(msg[0], 2)} 0x{toHex(msg[1], 2)} 0x{toHex(msg[2], 2)}"
|
|
||||||
|
case midiGetMessageType(msg[]):
|
||||||
|
of midiMsgNoteOff, midiMsgNoteOn, midiMsgNotePressure:
|
||||||
|
let noteOffset = clamp(floor(amp.transposition[] + 0.5), -12, 12).uint8
|
||||||
|
msg[1] = clamp(msg[1] + noteOffset, 0, 127).uint8
|
||||||
|
else:
|
||||||
|
discard
|
||||||
|
|
||||||
|
discard atomSequenceAppendEvent(amp.output, outCapacity, ev)
|
||||||
|
|
||||||
|
|
||||||
proc deactivate(instance: Lv2Handle) {.cdecl.} =
|
proc deactivate(instance: Lv2Handle) {.cdecl.} =
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
## See <http://lv2plug.in/ns/ext/atom> for details.
|
## See <http://lv2plug.in/ns/ext/atom> for details.
|
||||||
##
|
##
|
||||||
|
|
||||||
|
import ptrmath
|
||||||
|
|
||||||
const
|
const
|
||||||
lv2AtomBaseUri ="http://lv2plug.in/ns/ext/atom"
|
lv2AtomBaseUri ="http://lv2plug.in/ns/ext/atom"
|
||||||
lv2AtomPrefix = lv2AtomBaseUri & "#"
|
lv2AtomPrefix = lv2AtomBaseUri & "#"
|
||||||
|
@ -51,29 +53,12 @@ const
|
||||||
template atomContents*(`type`, atom: untyped): pointer =
|
template atomContents*(`type`, atom: untyped): pointer =
|
||||||
cast[ptr uint8](atom) + sizeof(`type`)
|
cast[ptr uint8](atom) + sizeof(`type`)
|
||||||
|
|
||||||
#[
|
|
||||||
{.push header: "lv2/atom/atom.h".}
|
|
||||||
|
|
||||||
var atomReferenceType* {.importc: "LV2_ATOM_REFERENCE_TYPE".}: int
|
|
||||||
|
|
||||||
##
|
|
||||||
## Const version of LV2_ATOM_CONTENTS.
|
|
||||||
##
|
|
||||||
proc atomContentsConst*(`type`: untyped; atom: untyped) {.importc: "LV2_ATOM_CONTENTS_CONST".}
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Return a pointer to the body of an Atom. The "body" of an atom is the
|
## Return a pointer to the body of an Atom. The "body" of an atom is the
|
||||||
## data just past the LV2_Atom head (i.e. the same offset for all types).
|
## data just past the Atom head (i.e. the same offset for all types).
|
||||||
##
|
##
|
||||||
proc atomBody*(atom: untyped) {.importc: "LV2_ATOM_BODY".}
|
template atomBody*(atom: untyped): pointer =
|
||||||
|
atomContents(Atom, atom)
|
||||||
##
|
|
||||||
## Const version of LV2_ATOM_BODY.
|
|
||||||
##
|
|
||||||
proc atomBodyConst*(atom: untyped) {.importc: "LV2_ATOM_BODY_CONST".}
|
|
||||||
|
|
||||||
{.pop.}
|
|
||||||
]#
|
|
||||||
|
|
||||||
type
|
type
|
||||||
## The header of an atom:Atom.
|
## The header of an atom:Atom.
|
||||||
|
@ -81,35 +66,35 @@ type
|
||||||
size*: uint32 ## Size in bytes, not including type and size.
|
size*: uint32 ## Size in bytes, not including type and size.
|
||||||
`type`*: uint32 ## of this atom (mapped URI).
|
`type`*: uint32 ## of this atom (mapped URI).
|
||||||
|
|
||||||
## An atom:Int or atom:Bool. May be cast to LV2_Atom.
|
## An atom:Int or atom:Bool. May be cast to Atom.
|
||||||
AtomInt* {.bycopy.} = object
|
AtomInt* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: int32 ## Integer value.
|
body*: int32 ## Integer value.
|
||||||
|
|
||||||
## An atom:Long. May be cast to LV2_Atom.
|
## An atom:Long. May be cast to Atom.
|
||||||
AtomLong* {.bycopy.} = object
|
AtomLong* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: int64 ## Integer value.
|
body*: int64 ## Integer value.
|
||||||
|
|
||||||
## An atom:Float. May be cast to LV2_Atom.
|
## An atom:Float. May be cast to Atom.
|
||||||
AtomFloat* {.bycopy.} = object
|
AtomFloat* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: cfloat ## Floating point value.
|
body*: cfloat ## Floating point value.
|
||||||
|
|
||||||
## An atom:Double. May be cast to LV2_Atom.
|
## An atom:Double. May be cast to Atom.
|
||||||
AtomDouble* {.bycopy.} = object
|
AtomDouble* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: cdouble ## Floating point value.
|
body*: cdouble ## Floating point value.
|
||||||
|
|
||||||
## An atom:Bool. May be cast to LV2_Atom.
|
## An atom:Bool. May be cast to Atom.
|
||||||
AtomBool* = distinct AtomInt
|
AtomBool* = distinct AtomInt
|
||||||
|
|
||||||
## An atom:URID. May be cast to LV2_Atom.
|
## An atom:URID. May be cast to Atom.
|
||||||
AtomUrid* {.bycopy.} = object
|
AtomUrid* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: uint32 ## URID.
|
body*: uint32 ## URID.
|
||||||
|
|
||||||
## An atom:String. May be cast to LV2_Atom.
|
## An atom:String. May be cast to Atom.
|
||||||
AtomString* {.bycopy.} = object
|
AtomString* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
## Contents (a null-terminated UTF-8 string) follow here.
|
## Contents (a null-terminated UTF-8 string) follow here.
|
||||||
|
@ -120,12 +105,12 @@ type
|
||||||
lang*: uint32 ## Language URID.
|
lang*: uint32 ## Language URID.
|
||||||
## Contents (a null-terminated UTF-8 string) follow here.
|
## Contents (a null-terminated UTF-8 string) follow here.
|
||||||
|
|
||||||
## An atom:Literal. May be cast to LV2_Atom.
|
## An atom:Literal. May be cast to Atom.
|
||||||
AtomLiteral* {.bycopy.} = object
|
AtomLiteral* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: AtomLiteralBody ## Body.
|
body*: AtomLiteralBody ## Body.
|
||||||
|
|
||||||
## An atom:Tuple. May be cast to LV2_Atom.
|
## An atom:Tuple. May be cast to Atom.
|
||||||
AtomTuple* {.bycopy.} = object
|
AtomTuple* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
## Contents (a series of complete atoms) follow here.
|
## Contents (a series of complete atoms) follow here.
|
||||||
|
@ -136,7 +121,7 @@ type
|
||||||
childType*: uint32 ## The of each element in the vector.
|
childType*: uint32 ## The of each element in the vector.
|
||||||
## Contents (a series of packed atom bodies) follow here.
|
## Contents (a series of packed atom bodies) follow here.
|
||||||
|
|
||||||
## An atom:Vector. May be cast to LV2_Atom.
|
## An atom:Vector. May be cast to Atom.
|
||||||
AtomVector* {.bycopy.} = object
|
AtomVector* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: AtomVectorBody ## Body.
|
body*: AtomVectorBody ## Body.
|
||||||
|
@ -148,23 +133,23 @@ type
|
||||||
value*: Atom ## Value atom header.
|
value*: Atom ## Value atom header.
|
||||||
## Value atom body follows here.
|
## Value atom body follows here.
|
||||||
|
|
||||||
## An atom:Property. May be cast to LV2_Atom.
|
## An atom:Property. May be cast to Atom.
|
||||||
AtomProperty* {.bycopy.} = object
|
AtomProperty* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: AtomPropertyBody ## Body.
|
body*: AtomPropertyBody ## Body.
|
||||||
|
|
||||||
## The body of an atom:Object. May be cast to LV2_Atom.
|
## The body of an atom:Object. May be cast to Atom.
|
||||||
AtomObjectBody* {.bycopy.} = object
|
AtomObjectBody* {.bycopy.} = object
|
||||||
id*: uint32 ## URID, or 0 for blank.
|
id*: uint32 ## URID, or 0 for blank.
|
||||||
otype*: uint32 ## URID (same as rdf:type, for fast dispatch).
|
otype*: uint32 ## URID (same as rdf:type, for fast dispatch).
|
||||||
## Contents (a series of property bodies) follow here.
|
## Contents (a series of property bodies) follow here.
|
||||||
|
|
||||||
## An atom:Object. May be cast to LV2_Atom.
|
## An atom:Object. May be cast to Atom.
|
||||||
AtomObject* {.bycopy.} = object
|
AtomObject* {.bycopy.} = object
|
||||||
atom*: Atom ## Atom header.
|
atom*: Atom ## Atom header.
|
||||||
body*: AtomObjectBody ## Body.
|
body*: AtomObjectBody ## Body.
|
||||||
|
|
||||||
## The header of an atom:Event. Note this is NOT an LV2_Atom.
|
## The header of an atom:Event. Note this is NOT an Atom.
|
||||||
AtomEventTime* {.bycopy, union.} = object
|
AtomEventTime* {.bycopy, union.} = object
|
||||||
frames*: int64 ## Time in audio frames.
|
frames*: int64 ## Time in audio frames.
|
||||||
beats*: cdouble ## Time in beats.
|
beats*: cdouble ## Time in beats.
|
||||||
|
@ -175,13 +160,13 @@ type
|
||||||
## Body atom contents follow here.
|
## Body atom contents follow here.
|
||||||
|
|
||||||
##
|
##
|
||||||
## The body of an atom:Sequence (a sequence of events).
|
## The body of an AtomSequence (a sequence of events).
|
||||||
##
|
##
|
||||||
## The unit field is either a URID that described an appropriate time stamp
|
## The unit field is either a Urid that described an appropriate time stamp
|
||||||
## type, or may be 0 where a default stamp is known. For
|
## type, or may be 0 where a default stamp is known. For
|
||||||
## LV2_Descriptor::run(), the default stamp is audio frames.
|
## lv2Descriptor.run(), the default stamp is audio frames.
|
||||||
##
|
##
|
||||||
## The contents of a sequence is a series of LV2_Atom_Event, each aligned
|
## The contents of a sequence is a series of AtomEvent, each aligned
|
||||||
## to 64-bits, for example:
|
## to 64-bits, for example:
|
||||||
## <pre>
|
## <pre>
|
||||||
## | Event 1 (size 6) | Event 2
|
## | Event 1 (size 6) | Event 2
|
||||||
|
|
|
@ -12,14 +12,7 @@
|
||||||
|
|
||||||
from system/ansi_c import c_memcmp, c_memcpy
|
from system/ansi_c import c_memcmp, c_memcpy
|
||||||
import ../atom
|
import ../atom
|
||||||
|
import ../ptrmath
|
||||||
|
|
||||||
##
|
|
||||||
## Increment pointer `p` by `offset` that jumps memory in increments of
|
|
||||||
## the size of `T`.
|
|
||||||
##
|
|
||||||
proc `+`*[T](p: ptr T, offset: SomeInteger): ptr T =
|
|
||||||
return cast[ptr T](cast[int](p) +% (offset.int * sizeof(T)))
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## Pad a size to 64 bits.
|
## Pad a size to 64 bits.
|
||||||
|
@ -73,7 +66,7 @@ proc atomSequenceIsEnd*(body: ptr AtomSequenceBody; size: Natural; i: ptr AtomEv
|
||||||
## Return an iterator to the element following `i`.
|
## Return an iterator to the element following `i`.
|
||||||
##
|
##
|
||||||
proc atomSequenceNext*(i: ptr AtomEvent): ptr AtomEvent {.inline.} =
|
proc atomSequenceNext*(i: ptr AtomEvent): ptr AtomEvent {.inline.} =
|
||||||
return cast[ptr AtomEvent](i + sizeof(AtomEvent) + atomPadSize(i.body.size))
|
return cast[ptr AtomEvent](cast[ptr uint8](i) + sizeof(AtomEvent) + atomPadSize(i.body.size))
|
||||||
|
|
||||||
##
|
##
|
||||||
## An iterator for looping over all events in a Sequence.
|
## An iterator for looping over all events in a Sequence.
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
##
|
||||||
|
## Increment pointer `p` by `offset` that jumps memory in increments of
|
||||||
|
## the size of `T`.
|
||||||
|
##
|
||||||
|
proc `+`*[T](p: ptr T, offset: SomeInteger): ptr T =
|
||||||
|
return cast[ptr T](cast[int](p) +% (offset.int * sizeof(T)))
|
|
@ -15,27 +15,23 @@ const
|
||||||
lv2UridUnmap* = lv2UridPrefix & "unmap"
|
lv2UridUnmap* = lv2UridPrefix & "unmap"
|
||||||
|
|
||||||
##
|
##
|
||||||
## Opaque pointer to host data for uridMap.
|
## Opaque pointer to host data for UridMap.
|
||||||
##
|
##
|
||||||
|
|
||||||
type UridMapHandle* = pointer
|
type UridMapHandle* = pointer
|
||||||
|
|
||||||
##
|
##
|
||||||
## Opaque pointer to host data for uridUnmap.
|
## Opaque pointer to host data for uridUnmap.
|
||||||
##
|
##
|
||||||
|
|
||||||
type UridUnmapHandle* = pointer
|
type UridUnmapHandle* = pointer
|
||||||
|
|
||||||
##
|
##
|
||||||
## URI mapped to an integer.
|
## URI mapped to an integer.
|
||||||
##
|
##
|
||||||
|
|
||||||
type Urid* = distinct uint32
|
type Urid* = distinct uint32
|
||||||
|
|
||||||
##
|
##
|
||||||
## URID Map Feature (LV2_URID__map)
|
## URID Map Feature (lv2UridMap)
|
||||||
##
|
##
|
||||||
|
|
||||||
type UridMap* {.bycopy.} = object
|
type UridMap* {.bycopy.} = object
|
||||||
##
|
##
|
||||||
## Opaque pointer to host data.
|
## Opaque pointer to host data.
|
||||||
|
@ -67,11 +63,9 @@ type UridMap* {.bycopy.} = object
|
||||||
##
|
##
|
||||||
map*: proc (handle: UridMapHandle; uri: cstring): Urid
|
map*: proc (handle: UridMapHandle; uri: cstring): Urid
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## URI Unmap Feature (LV2_URID__unmap)
|
## URI Unmap Feature (lv2UridUnmap)
|
||||||
##
|
##
|
||||||
|
|
||||||
type UridUnmap* {.bycopy.} = object
|
type UridUnmap* {.bycopy.} = object
|
||||||
##
|
##
|
||||||
## Opaque pointer to host data.
|
## Opaque pointer to host data.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import ../nymph
|
import core
|
||||||
|
|
||||||
## Return the data for a feature in a features array.
|
## Return the data for a feature in a features array.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue