diff --git a/examples/amp.lv2/amp.ttl b/examples/amp.lv2/amp.ttl index 4b3fd3d..081ed6b 100644 --- a/examples/amp.lv2/amp.ttl +++ b/examples/amp.lv2/amp.ttl @@ -6,12 +6,15 @@ @prefix params: . @prefix rdfs: . @prefix units: . +@prefix urid: . a lv2:Plugin , lv2:AmplifierPlugin , doap:Project ; lv2:optionalFeature lv2:hardRTCapable , bufs:boundedBlockLength , opts:options ; + lv2:requiredFeature urid:map ; + opts:supportedOption bufs:nominalBlockLength , bufs:maxBlockLength , params:sampleRate ; diff --git a/examples/amp_plugin.nim b/examples/amp_plugin.nim index 7cae9d0..209f397 100644 --- a/examples/amp_plugin.nim +++ b/examples/amp_plugin.nim @@ -1,7 +1,7 @@ ## A simple amplifier LV2 plugin -import std/math -import nymph +import std/[math, strformat] +import nymph/[core, log, urid, util] const PluginUri = "urn:nymph:examples:amp" @@ -14,6 +14,8 @@ type AmpPlugin = object input: ptr SampleBuffer output: ptr SampleBuffer + map: ptr UridMap + log: Logger gain: ptr cfloat @@ -25,38 +27,53 @@ proc instantiate(descriptor: ptr Lv2Descriptor; sampleRate: cdouble; bundlePath: cstring; features: ptr UncheckedArray[ptr Lv2Feature]): Lv2Handle {.cdecl.} = try: - return createShared(AmpPlugin) + let plug: ptr AmpPlugin = createShared(AmpPlugin) + + plug.map = cast[ptr UridMap](lv2FeaturesData(features, lv2UridMap)) + + if plug.map.isNil: + freeShared(plug) + return nil + + let logPtr = cast[ptr Log](lv2FeaturesData(features, lv2LogLog)) + plug.log.init(logPtr, plug.map) + plug.log.note("nymph amp plugin instance created.") + return cast[Lv2Handle](plug) except OutOfMemDefect: return nil proc connectPort(instance: Lv2Handle; port: cuint; dataLocation: pointer) {.cdecl.} = - let amp = cast[ptr AmpPlugin](instance) + let plug = cast[ptr AmpPlugin](instance) case cast[PluginPort](port) of PluginPort.Input: - amp.input = cast[ptr SampleBuffer](dataLocation) + plug.input = cast[ptr SampleBuffer](dataLocation) of PluginPort.Output: - amp.output = cast[ptr SampleBuffer](dataLocation) + plug.output = cast[ptr SampleBuffer](dataLocation) of PluginPort.Gain: - amp.gain = cast[ptr cfloat](dataLocation) + plug.gain = cast[ptr cfloat](dataLocation) proc activate(instance: Lv2Handle) {.cdecl.} = - discard + let plug = cast[ptr AmpPlugin](instance) + plug.log.note("nymph amp plugin activated.") proc run(instance: Lv2Handle; nSamples: cuint) {.cdecl.} = - let amp = cast[ptr AmpPlugin](instance) + let plug = cast[ptr AmpPlugin](instance) for pos in 0 ..< nSamples: - amp.output[pos] = amp.input[pos] * db2coeff(amp.gain[]) + plug.output[pos] = plug.input[pos] * db2coeff(plug.gain[]) proc deactivate(instance: Lv2Handle) {.cdecl.} = - discard + let plug = cast[ptr AmpPlugin](instance) + plug.log.note("nymph amp plugin deactivated.") proc cleanup(instance: Lv2Handle) {.cdecl.} = + let plug = cast[ptr AmpPlugin](instance) + plug.log.note("De-allocating nymph amp plugin instance.") freeShared(cast[ptr AmpPlugin](instance)) @@ -80,6 +97,9 @@ let descriptor = Lv2Descriptor( proc lv2Descriptor(index: cuint): ptr Lv2Descriptor {. cdecl, exportc, dynlib, extern: "lv2_descriptor".} = + + echo fmt"nymph am plugin descriptor #{index} requested" + if index == 0: NimMain() return addr(descriptor) diff --git a/src/nymph/log.nim b/src/nymph/log.nim new file mode 100644 index 0000000..17523df --- /dev/null +++ b/src/nymph/log.nim @@ -0,0 +1,70 @@ +## Copyright 2012-2016 David Robillard +## SPDX-License-Identifier: ISC +## +## Interface for plugins to log via the host. +## +## See for details. +## + +import urid + +type va_list* {.importc: "va_list", header: "".} = object + +const + lv2LogBaseUri* = "http://lv2plug.in/ns/ext/log" + lv2LogPrefix = lv2LogBaseUri & "#" + lv2LogEntry* = lv2LogPrefix & "Entry" + lv2LogError* = lv2LogPrefix & "Error" + lv2LogNote* = lv2LogPrefix & "Note" + lv2LogTrace* = lv2LogPrefix & "Trace" + lv2LogWarning* = lv2LogPrefix & "Warning" + lv2LogLog* = lv2LogPrefix & "log" + +type + LogHandle* = distinct pointer + + Log* = object + handle: LogHandle + printf*: proc(handle: LogHandle, `type`: Urid, fmt: cstring) {.cdecl, varargs.} + + Logger* = object + pLog: ptr Log + Error, Note, Trace, Warning: Urid + + +proc init*(logger: var Logger, log: ptr Log, map: ptr UridMap) = + logger.pLog = log + + if not map.isNil: + logger.Error = map.map(map.handle, lv2LogError) + logger.Note = map.map(map.handle, lv2LogNote) + logger.Trace = map.map(map.handle, lv2LogTrace) + logger.Warning = map.map(map.handle, lv2LogWarning) + else: + logger.Error = Urid(0) + logger.Note = Urid(0) + logger.Trace = Urid(0) + logger.Warning = Urid(0) + + +proc log*(logger: Logger, `type`: Urid, msg: string) = + if logger.pLog.isNil: + echo(msg) + else: + logger.pLog.printf(logger.pLog.handle, `type`, msg.cstring) + + +proc error*(logger: Logger, msg: string) = + log(logger, logger.Error, msg) + + +proc note*(logger: Logger, msg: string) = + log(logger, logger.Note, msg) + + +proc trace*(logger: Logger, msg: string) = + log(logger, logger.Trace, msg) + + +proc warning*(logger: Logger, msg: string) = + log(logger, logger.Warning, msg)