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/util
|
||||
|
||||
|
@ -18,27 +20,17 @@ type
|
|||
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;
|
||||
bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]):
|
||||
Lv2Handle {.cdecl.} =
|
||||
printFeatures(features)
|
||||
let amp: ptr MidiTransposePlugin = createShared(MidiTransposePlugin)
|
||||
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)
|
||||
echo &"{lv2MidiMidiEvent} = {amp.midi_urid.int}"
|
||||
|
||||
return cast[Lv2Handle](amp)
|
||||
|
||||
|
||||
|
@ -53,18 +45,33 @@ proc connectPort(instance: Lv2Handle; port: cuint;
|
|||
of PluginPort.Transposition:
|
||||
amp.transposition = cast[ptr cfloat](dataLocation)
|
||||
|
||||
|
||||
proc activate(instance: Lv2Handle) {.cdecl.} =
|
||||
discard
|
||||
|
||||
|
||||
proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} =
|
||||
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:
|
||||
#echo &"Event sequence size: {amp.input.atom.size}"
|
||||
|
||||
for ev in items(amp.input):
|
||||
if Urid(ev.body.`type`) == amp.midi_urid:
|
||||
# TODO
|
||||
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)}"
|
||||
var msg = cast[ptr UncheckedArray[uint8]](atomContents(AtomEvent, ev))
|
||||
#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.} =
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
## See <http://lv2plug.in/ns/ext/atom> for details.
|
||||
##
|
||||
|
||||
import ptrmath
|
||||
|
||||
const
|
||||
lv2AtomBaseUri ="http://lv2plug.in/ns/ext/atom"
|
||||
lv2AtomPrefix = lv2AtomBaseUri & "#"
|
||||
|
@ -51,29 +53,12 @@ const
|
|||
template atomContents*(`type`, atom: untyped): pointer =
|
||||
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
|
||||
## 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".}
|
||||
|
||||
##
|
||||
## Const version of LV2_ATOM_BODY.
|
||||
##
|
||||
proc atomBodyConst*(atom: untyped) {.importc: "LV2_ATOM_BODY_CONST".}
|
||||
|
||||
{.pop.}
|
||||
]#
|
||||
template atomBody*(atom: untyped): pointer =
|
||||
atomContents(Atom, atom)
|
||||
|
||||
type
|
||||
## The header of an atom:Atom.
|
||||
|
@ -81,35 +66,35 @@ type
|
|||
size*: uint32 ## Size in bytes, not including type and size.
|
||||
`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
|
||||
atom*: Atom ## Atom header.
|
||||
body*: int32 ## Integer value.
|
||||
|
||||
## An atom:Long. May be cast to LV2_Atom.
|
||||
## An atom:Long. May be cast to Atom.
|
||||
AtomLong* {.bycopy.} = object
|
||||
atom*: Atom ## Atom header.
|
||||
body*: int64 ## Integer value.
|
||||
|
||||
## An atom:Float. May be cast to LV2_Atom.
|
||||
## An atom:Float. May be cast to Atom.
|
||||
AtomFloat* {.bycopy.} = object
|
||||
atom*: Atom ## Atom header.
|
||||
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
|
||||
atom*: Atom ## Atom header.
|
||||
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
|
||||
|
||||
## An atom:URID. May be cast to LV2_Atom.
|
||||
## An atom:URID. May be cast to Atom.
|
||||
AtomUrid* {.bycopy.} = object
|
||||
atom*: Atom ## Atom header.
|
||||
body*: uint32 ## URID.
|
||||
|
||||
## An atom:String. May be cast to LV2_Atom.
|
||||
## An atom:String. May be cast to Atom.
|
||||
AtomString* {.bycopy.} = object
|
||||
atom*: Atom ## Atom header.
|
||||
## Contents (a null-terminated UTF-8 string) follow here.
|
||||
|
@ -120,12 +105,12 @@ type
|
|||
lang*: uint32 ## Language URID.
|
||||
## 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
|
||||
atom*: Atom ## Atom header.
|
||||
body*: AtomLiteralBody ## Body.
|
||||
|
||||
## An atom:Tuple. May be cast to LV2_Atom.
|
||||
## An atom:Tuple. May be cast to Atom.
|
||||
AtomTuple* {.bycopy.} = object
|
||||
atom*: Atom ## Atom header.
|
||||
## Contents (a series of complete atoms) follow here.
|
||||
|
@ -136,7 +121,7 @@ type
|
|||
childType*: uint32 ## The of each element in the vector.
|
||||
## 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
|
||||
atom*: Atom ## Atom header.
|
||||
body*: AtomVectorBody ## Body.
|
||||
|
@ -148,23 +133,23 @@ type
|
|||
value*: Atom ## Value atom header.
|
||||
## 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
|
||||
atom*: Atom ## Atom header.
|
||||
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
|
||||
id*: uint32 ## URID, or 0 for blank.
|
||||
otype*: uint32 ## URID (same as rdf:type, for fast dispatch).
|
||||
## 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
|
||||
atom*: Atom ## Atom header.
|
||||
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
|
||||
frames*: int64 ## Time in audio frames.
|
||||
beats*: cdouble ## Time in beats.
|
||||
|
@ -175,13 +160,13 @@ type
|
|||
## 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
|
||||
## 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:
|
||||
## <pre>
|
||||
## | Event 1 (size 6) | Event 2
|
||||
|
|
|
@ -12,14 +12,7 @@
|
|||
|
||||
from system/ansi_c import c_memcmp, c_memcpy
|
||||
import ../atom
|
||||
|
||||
|
||||
##
|
||||
## 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)))
|
||||
import ../ptrmath
|
||||
|
||||
##
|
||||
## 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`.
|
||||
##
|
||||
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.
|
||||
|
|
|
@ -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"
|
||||
|
||||
##
|
||||
## Opaque pointer to host data for uridMap.
|
||||
## Opaque pointer to host data for UridMap.
|
||||
##
|
||||
|
||||
type UridMapHandle* = pointer
|
||||
|
||||
##
|
||||
## Opaque pointer to host data for uridUnmap.
|
||||
##
|
||||
|
||||
type UridUnmapHandle* = pointer
|
||||
|
||||
##
|
||||
## URI mapped to an integer.
|
||||
##
|
||||
|
||||
type Urid* = distinct uint32
|
||||
|
||||
##
|
||||
## URID Map Feature (LV2_URID__map)
|
||||
## URID Map Feature (lv2UridMap)
|
||||
##
|
||||
|
||||
type UridMap* {.bycopy.} = object
|
||||
##
|
||||
## Opaque pointer to host data.
|
||||
|
@ -67,11 +63,9 @@ type UridMap* {.bycopy.} = object
|
|||
##
|
||||
map*: proc (handle: UridMapHandle; uri: cstring): Urid
|
||||
|
||||
|
||||
##
|
||||
## URI Unmap Feature (LV2_URID__unmap)
|
||||
## URI Unmap Feature (lv2UridUnmap)
|
||||
##
|
||||
|
||||
type UridUnmap* {.bycopy.} = object
|
||||
##
|
||||
## Opaque pointer to host data.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import ../nymph
|
||||
import core
|
||||
|
||||
## Return the data for a feature in a features array.
|
||||
|
||||
|
|
Loading…
Reference in New Issue