From a6c3fc024ca518a493195c4b616d924b8a65d408 Mon Sep 17 00:00:00 2001 From: haruki7049 Date: Tue, 1 Jul 2025 00:42:18 +0900 Subject: [PATCH 1/9] Update build.zig syntaxes for Zig-0.14.0 --- .gitignore | 24 ++++++++++++++++++++++-- build.zig | 55 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/.gitignore b/.gitignore index d4224e5..7e9e158 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,22 @@ -/zig-cache -/zig-out +# This file is for zig-specific build artifacts. +# If you have OS-specific or editor-specific files to ignore, +# such as *.swp or .DS_Store, put those in your global +# ~/.gitignore and put this in your ~/.gitconfig: +# +# [core] +# excludesfile = ~/.gitignore +# +# Cheers! +# -andrewrk + +.zig-cache/ +zig-out/ +/release/ +/debug/ +/build/ +/build-*/ +/docgen_tmp/ + +# Although this was renamed to .zig-cache, let's leave it here for a few +# releases to make it less annoying to work with multiple branches. +zig-cache/ diff --git a/build.zig b/build.zig index ac163e6..c013bc5 100644 --- a/build.zig +++ b/build.zig @@ -1,21 +1,46 @@ const std = @import("std"); -const Builder = @import("std").build.Builder; const examples = &[_][]const u8{"amp", "fifths", "params"}; -pub fn build(b: *Builder) !void { - const mode = b.standardReleaseOptions(); - inline for (examples) |example, i| { - const lib = b.addSharedLibrary(example, "examples/" ++ example ++ "/" ++ example ++ ".zig", .{ .unversioned = {} }); - - lib.addPackagePath("lv2", "src/lv2.zig"); - lib.setBuildMode(mode); - lib.setOutputDir("zig-out/" ++ example ++ ".lv2"); - lib.linkLibC(); - lib.addIncludeDir("lv2"); - - var step = b.step(example, "Build example \"" ++ example ++ "\""); - step.dependOn(&b.addInstallFileWithDir("examples/" ++ example ++ "/" ++ example ++ ".ttl", .Prefix, example ++ ".lv2/manifest.ttl").step); - step.dependOn(&lib.step); +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // Library module + const lib_mod = b.createModule(.{ + .root_source_file = b.path("src/lv2.zig"), + .target = target, + .optimize = optimize, + }); + + // Library + const lib = b.addLibrary(.{ + .linkage = .static, + .name = "lv2", + .root_module = lib_mod, + }); + + // Link lv2 library + lib.linkLibC(); + lib.addIncludePath(b.path("lv2")); + + // Unit tests for library + const lib_unit_tests = b.addTest(.{ + .root_module = lib_mod, + }); + + + const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + + // Test step + const test_step = b.step("test", "Run unit tests"); + test_step.dependOn(&run_lib_unit_tests.step); + + // Example generate step + const examples_step = b.step("examples", "Build examples"); + inline for (examples) |example| { + const source = b.path("examples/" ++ example ++ "/" ++ example ++ ".ttl"); + const dest = example ++ ".lv2/mainfest.ttl"; + examples_step.dependOn(&b.addInstallFileWithDir(source, .prefix, dest).step); } } From aa2c84af84119ab83411682c8200df2870ad562f Mon Sep 17 00:00:00 2001 From: haruki7049 Date: Tue, 1 Jul 2025 00:44:16 +0900 Subject: [PATCH 2/9] Append build.zig.zon --- build.zig.zon | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 build.zig.zon diff --git a/build.zig.zon b/build.zig.zon new file mode 100644 index 0000000..d978546 --- /dev/null +++ b/build.zig.zon @@ -0,0 +1,75 @@ +.{ + // This is the default name used by packages depending on this one. For + // example, when a user runs `zig fetch --save `, this field is used + // as the key in the `dependencies` table. Although the user can choose a + // different name, most users will stick with this provided value. + // + // It is redundant to include "zig" in this name because it is already + // within the Zig package namespace. + .name = .lv2, + + // This is a [Semantic Version](https://semver.org/). + // In a future version of Zig it will be used for package deduplication. + .version = "0.0.0", + + // Together with name, this represents a globally unique package + // identifier. This field is generated by the Zig toolchain when the + // package is first created, and then *never changes*. This allows + // unambiguous detection of one package being an updated version of + // another. + // + // When forking a Zig project, this id should be regenerated (delete the + // field and run `zig build`) if the upstream project is still maintained. + // Otherwise, the fork is *hostile*, attempting to take control over the + // original project's identity. Thus it is recommended to leave the comment + // on the following line intact, so that it shows up in code reviews that + // modify the field. + .fingerprint = 0xf3e64a61a3cf623, // Changing this has security and trust implications. + + // Tracks the earliest Zig version that the package considers to be a + // supported use case. + .minimum_zig_version = "0.14.1", + + // This field is optional. + // Each dependency must either provide a `url` and `hash`, or a `path`. + // `zig build --fetch` can be used to fetch all dependencies of a package, recursively. + // Once all dependencies are fetched, `zig build` no longer requires + // internet connectivity. + .dependencies = .{ + // See `zig fetch --save ` for a command-line interface for adding dependencies. + //.example = .{ + // // When updating this field to a new URL, be sure to delete the corresponding + // // `hash`, otherwise you are communicating that you expect to find the old hash at + // // the new URL. If the contents of a URL change this will result in a hash mismatch + // // which will prevent zig from using it. + // .url = "https://example.com/foo.tar.gz", + // + // // This is computed from the file contents of the directory of files that is + // // obtained after fetching `url` and applying the inclusion rules given by + // // `paths`. + // // + // // This field is the source of truth; packages do not come from a `url`; they + // // come from a `hash`. `url` is just one of many possible mirrors for how to + // // obtain a package matching this `hash`. + // // + // // Uses the [multihash](https://multiformats.io/multihash/) format. + // .hash = "...", + // + // // When this is provided, the package is found in a directory relative to the + // // build root. In this case the package's hash is irrelevant and therefore not + // // computed. This field and `url` are mutually exclusive. + // .path = "foo", + // + // // When this is set to `true`, a package is declared to be lazily + // // fetched. This makes the dependency only get fetched if it is + // // actually used. + // .lazy = false, + //}, + }, + + .paths = .{ + "build.zig", + "build.zig.zon", + "src", + }, +} From 6995949b7ece0a53114f1006389ebf1625192de9 Mon Sep 17 00:00:00 2001 From: haruki7049 Date: Tue, 1 Jul 2025 00:45:58 +0900 Subject: [PATCH 3/9] Add Zig version info in README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8f4db43..1090c1e 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ A toolkit for LV2 plugin authors written in Zig. **WARNING: Here be dragons; tons of LV2 features aren't implemented and this isn't ready for production at all.** +## Zig version +Zig 0.14.0 + ## Installing ```bash git clone --recurse-submodules https://github.com/ziglibs/zig-lv2 From e6ee7af5f494190f5260b97c4fd6d2d4b61b89fb Mon Sep 17 00:00:00 2001 From: esteban Date: Thu, 24 Jul 2025 22:20:36 +0200 Subject: [PATCH 4/9] WIP: amp and fifths work on javl and carla --- build.zig | 22 ++++++++++++-- examples/amp/amp.ttl | 4 +-- examples/amp/amp.zig | 1 - examples/fifths/fifths.ttl | 4 +-- examples/fifths/fifths.zig | 6 +++- ext_lv2/atom_util.c | 54 +++++++++++++++++++++++++++++++++ ext_lv2/atom_util.h | 38 ++++++++++++++++++++++++ src/atom/atom.zig | 26 ++++++++-------- src/atom/forge.zig | 51 +++++++++++++++++-------------- src/c.zig | 3 +- src/lv2.zig | 61 +++++++++++++++++++++++--------------- src/state.zig | 56 ++++++++++++++++++++-------------- src/urid.zig | 16 +++++----- src/utils.zig | 33 ++++++++++++++------- 14 files changed, 265 insertions(+), 110 deletions(-) create mode 100644 ext_lv2/atom_util.c create mode 100644 ext_lv2/atom_util.h diff --git a/build.zig b/build.zig index c013bc5..50f3292 100644 --- a/build.zig +++ b/build.zig @@ -1,6 +1,8 @@ const std = @import("std"); const examples = &[_][]const u8{"amp", "fifths", "params"}; +//const examples = &[_][]const u8{"amp", "fifths"}; +//const examples = &[_][]const u8{"amp"}; pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); @@ -13,16 +15,21 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }); + //const ext_lv2 = b.dependency("ext_lv2", .{}); + lib_mod.addCSourceFile(.{ + .file = b.path("ext_lv2/atom_util.c") + }); + // Library const lib = b.addLibrary(.{ .linkage = .static, .name = "lv2", .root_module = lib_mod, }); - // Link lv2 library lib.linkLibC(); lib.addIncludePath(b.path("lv2")); + lib.addIncludePath(b.path("ext_lv2")); // Unit tests for library const lib_unit_tests = b.addTest(.{ @@ -40,7 +47,18 @@ pub fn build(b: *std.Build) !void { const examples_step = b.step("examples", "Build examples"); inline for (examples) |example| { const source = b.path("examples/" ++ example ++ "/" ++ example ++ ".ttl"); - const dest = example ++ ".lv2/mainfest.ttl"; + const dest = example ++ ".lv2/manifest.ttl"; + examples_step.dependOn(&b.addInstallFileWithDir(source, .prefix, dest).step); + + const dll = b.addSharedLibrary(.{ + .name = example, + .root_source_file = b.path("examples/" ++ example ++ "/" ++ example ++ ".zig"), + .target = target, + .optimize = optimize, + .version = .{ .major = 0, .minor = 0, .patch = 2 }, + }); + dll.root_module.addImport("lv2", lib_mod); + b.installArtifact(dll); } } diff --git a/examples/amp/amp.ttl b/examples/amp/amp.ttl index 4113d85..8de93ac 100644 --- a/examples/amp/amp.ttl +++ b/examples/amp/amp.ttl @@ -6,7 +6,7 @@ a lv2:Plugin, lv2:AmplifierPlugin; - lv2:binary ; + lv2:binary ; doap:name "Amp"; doap:license ; @@ -51,4 +51,4 @@ lv2:index 2; lv2:symbol "output"; lv2:name "Output"; - ]. \ No newline at end of file + ]. diff --git a/examples/amp/amp.zig b/examples/amp/amp.zig index ab01ca5..bf2f8af 100644 --- a/examples/amp/amp.zig +++ b/examples/amp/amp.zig @@ -22,7 +22,6 @@ fn decibelsToCoeff(g: f32) f32 { fn run(handle: *Amp.Handle, samples: u32) void { const coef = decibelsToCoeff(handle.gain.*); - var i: usize = 0; while (i < samples) : (i += 1) { handle.output[i] = handle.input[i] * coef; diff --git a/examples/fifths/fifths.ttl b/examples/fifths/fifths.ttl index fd409fd..09c90f7 100644 --- a/examples/fifths/fifths.ttl +++ b/examples/fifths/fifths.ttl @@ -6,7 +6,7 @@ a lv2:Plugin ; - lv2:binary ; + lv2:binary ; doap:name "Fifths" ; doap:license ; @@ -29,4 +29,4 @@ lv2:index 1 ; lv2:symbol "out" ; lv2:name "Out" - ] . \ No newline at end of file + ] . diff --git a/examples/fifths/fifths.zig b/examples/fifths/fifths.zig index 72229a3..3923a75 100644 --- a/examples/fifths/fifths.zig +++ b/examples/fifths/fifths.zig @@ -50,6 +50,9 @@ fn instantiate ( bundle_path: []const u8, features: lv2.Features ) anyerror!void { + _ = bundle_path; + _ = descriptor; + _ = rate; handle.map = features.query(lv2.URIDMap).?; handle.uris.map(handle.map); @@ -67,6 +70,7 @@ const MidiNoteEvent = extern struct { }; fn run(handle: *Fifths.Handle, samples: u32) void { + _ = samples; const out_size = handle.out.atom.size; handle.out.clear(); handle.out.atom.kind = handle.in.atom.kind; @@ -76,7 +80,7 @@ fn run(handle: *Fifths.Handle, samples: u32) void { if (event.body.kind == handle.uris.midi_event) { _ = handle.out.appendEvent(out_size, event) catch @panic("Error appending!"); - var data = event.getDataAs(*MidiNoteData); + const data = event.getDataAs(*MidiNoteData); var fifth = std.mem.zeroes(MidiNoteEvent); fifth.event.time.frames = event.time.frames; diff --git a/ext_lv2/atom_util.c b/ext_lv2/atom_util.c new file mode 100644 index 0000000..88c12cc --- /dev/null +++ b/ext_lv2/atom_util.c @@ -0,0 +1,54 @@ +#include "atom_util.h" + +extern LV2_Atom_Event* +ext_lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) +{ + return lv2_atom_sequence_begin(body); +}; + +extern LV2_Atom_Property_Body* +ext_lv2_atom_object_next(const LV2_Atom_Property_Body* i) +{ + return lv2_atom_object_next(i); +} + +extern bool +ext_lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, + uint32_t size, + const LV2_Atom_Property_Body* i) +{ + return lv2_atom_object_is_end(body, size, i); +}; + +extern void +ext_lv2_atom_sequence_clear(LV2_Atom_Sequence* seq) { + lv2_atom_sequence_clear(seq); +} + +extern LV2_Atom_Event* +ext_lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, + uint32_t capacity, + const LV2_Atom_Event* event) +{ + return lv2_atom_sequence_append_event(seq, capacity, event); +} + +extern LV2_Atom_Event* +ext_lv2_atom_sequence_next(const LV2_Atom_Event* i) +{ + return lv2_atom_sequence_next(i); +} + +extern LV2_Atom_Property_Body* +ext_lv2_atom_object_begin(const LV2_Atom_Object_Body* body) +{ + return lv2_atom_object_begin(body); +} + +extern bool +ext_lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, + uint32_t size, + const LV2_Atom_Event* i) +{ + return lv2_atom_sequence_is_end(body, size, i); +} diff --git a/ext_lv2/atom_util.h b/ext_lv2/atom_util.h new file mode 100644 index 0000000..447a0c1 --- /dev/null +++ b/ext_lv2/atom_util.h @@ -0,0 +1,38 @@ +#ifndef ATOM_UTIL_H +#define ATOM_UTIL_H + +#include "../lv2/lv2/atom/util.h" + +LV2_Atom_Event* +ext_lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body); + +LV2_Atom_Property_Body* +ext_lv2_atom_object_next(const LV2_Atom_Property_Body* i); + +bool +ext_lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, + uint32_t size, + const LV2_Atom_Property_Body* i); + +void +ext_lv2_atom_sequence_clear(LV2_Atom_Sequence* seq); + +LV2_Atom_Event* +ext_lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, + uint32_t capacity, + const LV2_Atom_Event* event); + +LV2_Atom_Event* +ext_lv2_atom_sequence_next(const LV2_Atom_Event* i); + +LV2_Atom_Property_Body* +ext_lv2_atom_object_begin(const LV2_Atom_Object_Body* body); + +bool +ext_lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, + uint32_t size, + const LV2_Atom_Event* i); + +#endif + + diff --git a/src/atom/atom.zig b/src/atom/atom.zig index 5fbb19e..65a0bcf 100644 --- a/src/atom/atom.zig +++ b/src/atom/atom.zig @@ -22,7 +22,7 @@ pub const AtomPropertyBody = extern struct { value: Atom, pub fn init(event: *c.LV2_Atom_Property_Body) *Self { - return @ptrCast(*Self, event); + return @ptrCast(event); } }; @@ -38,7 +38,7 @@ pub const AtomObject = extern struct { body: AtomObjectBody, pub fn iterator(self: *Self) AtomObjectIterator { - return AtomObjectIterator.init(@ptrCast(*c.LV2_Atom_Object, self)); + return AtomObjectIterator.init(@ptrCast(self)); } pub fn query(self: *Self, queries: []AtomObjectQuery) void { @@ -68,8 +68,8 @@ pub const AtomObjectIterator = struct { } pub fn next(self: *Self) ?*AtomPropertyBody { - self.last = if (self.last) |last| c.lv2_atom_object_next(last) else c.lv2_atom_object_begin(&self.object.body); - if (c.lv2_atom_object_is_end(&self.object.body, self.object.atom.size, self.last)) return null; + self.last = if (self.last) |last| c.ext_lv2_atom_object_next(last) else c.ext_lv2_atom_object_begin(&self.object.body); + if (c.ext_lv2_atom_object_is_end(&self.object.body, self.object.atom.size, self.last)) return null; return if (self.last) |l| AtomPropertyBody.init(l) else null; } }; @@ -86,15 +86,15 @@ pub const AtomEvent = extern struct { body: Atom, pub fn init(event: *c.LV2_Atom_Event) *Self { - return @ptrCast(*Self, event); + return @ptrCast(event); } pub fn getDataAs(self: *Self, comptime T: type) T { - return @intToPtr(T, @ptrToInt(self) + @sizeOf(Self)); + return @ptrFromInt(@intFromPtr(self) + @sizeOf(Self)); } pub fn toAtomObject(self: *Self) *AtomObject { - return @ptrCast(*AtomObject, &self.body); + return @ptrCast(&self.body); } }; @@ -112,20 +112,20 @@ pub const AtomSequence = extern struct { body: AtomSequenceBody, pub fn iterator(self: *Self) AtomSequenceIterator { - return AtomSequenceIterator.init(@ptrCast(*c.LV2_Atom_Sequence, self)); + return AtomSequenceIterator.init(@ptrCast(self)); } pub fn clear(self: *Self) void { - c.lv2_atom_sequence_clear(@ptrCast(*c.LV2_Atom_Sequence, self)); + c.ext_lv2_atom_sequence_clear(@ptrCast(self)); } pub fn appendEvent(self: *Self, out_size: u32, event: *AtomEvent) !*AtomEvent { - var maybe_appended_event = c.lv2_atom_sequence_append_event(@ptrCast(*c.LV2_Atom_Sequence, self), out_size, @ptrCast(*c.LV2_Atom_Event, event)); + const maybe_appended_event = c.ext_lv2_atom_sequence_append_event(@ptrCast(self), out_size, @ptrCast(event)); return if (maybe_appended_event) |appended_event| AtomEvent.init(appended_event) else error.AppendError; } pub fn toBuffer(self: *Self) [*c]u8 { - return @ptrCast([*c]u8, self); + return @ptrCast(self); } }; @@ -143,8 +143,8 @@ pub const AtomSequenceIterator = struct { } pub fn next(self: *Self) ?*AtomEvent { - self.last = if (self.last) |last| c.lv2_atom_sequence_next(last) else c.lv2_atom_sequence_begin(&self.seq.body); - if (c.lv2_atom_sequence_is_end(&self.seq.body, self.seq.atom.size, self.last)) return null; + self.last = if (self.last) |last| c.ext_lv2_atom_sequence_next(last) else c.ext_lv2_atom_sequence_begin(&self.seq.body); + if (c.ext_lv2_atom_sequence_is_end(&self.seq.body, self.seq.atom.size, self.last)) return null; return if (self.last) |l| AtomEvent.init(l) else null; } }; diff --git a/src/atom/forge.zig b/src/atom/forge.zig index 09cade1..0e15a63 100644 --- a/src/atom/forge.zig +++ b/src/atom/forge.zig @@ -3,9 +3,9 @@ const std = @import("std"); const atom = @import("atom.zig"); const urid = @import("../urid.zig"); -pub const AtomForgeSinkHandle = ?*c_void; +pub const AtomForgeSinkHandle = ?*anyopaque; pub const AtomForgeRef = isize; -pub const AtomForgeSink = ?fn (sink_handle: AtomForgeSinkHandle, buf: ?*const c_void, size: u32) callconv(.C) AtomForgeRef; +pub const AtomForgeSink = ?fn (sink_handle: AtomForgeSinkHandle, buf: ?*const anyopaque, size: u32) callconv(.C) AtomForgeRef; pub const AtomForgeDerefFunc = ?fn (sink_handle: AtomForgeSinkHandle, ref: AtomForgeRef) callconv(.C) [*c]atom.Atom; pub const AtomForgeFrame = extern struct { @@ -74,7 +74,7 @@ pub const AtomForge = extern struct { /// Access the Atom pointed to by a reference. pub fn deref(self: *Self, ref: AtomForgeRef) *atom.Atom { if (ref < 0) @panic("huh"); - return if (self.buf != null) @intToPtr(*atom.Atom, std.math.absCast(ref)) else self.deref_func.?(self.sink_handle, ref); + return if (self.buf != null) @ptrFromInt(std.math.absCast(ref)) else self.deref_func.?(self.sink_handle, ref); } /// Push a stack frame. Automatically handled by container functions. @@ -118,7 +118,7 @@ pub const AtomForge = extern struct { /// Set forge buffer. pub fn setBuffer(self: *Self, buf: [*c]u8, size: usize) void { self.buf = buf; - self.size = @truncate(u32, size); + self.size = @truncate(size); self.offset = 0; self.deref_func = null; self.sink = null; @@ -127,31 +127,32 @@ pub const AtomForge = extern struct { } /// Set forge sink. - pub fn setSink(self: *Self, sink: AtomForgeSink, deref: AtomForgeDerefFunc, sink_handle: AtomForgeSinkHandle) void { + pub fn setSink(self: *Self, sink: AtomForgeSink, deref_arg: AtomForgeDerefFunc, sink_handle: AtomForgeSinkHandle) void { self.buf = null; self.size = 0; self.offset = 0; - self.deref_func = deref; + self.deref_func = deref_arg; self.sink = sink; self.sink_handle = sink_handle; } /// Writes raw output. - pub fn raw(self: *Self, data: ?*const c_void, size: u32) AtomForgeRef { + pub fn raw(self: *Self, data: ?*const anyopaque, size: u32) AtomForgeRef { var out: AtomForgeRef = 0; - + if (self.sink) |sink| { out = sink(self.sink_handle, data, size); } else { - out = @intCast(AtomForgeRef, @ptrToInt(self.buf)) + @bitCast(c_longlong, @as(c_ulonglong, self.offset)); - var mem: *u8 = self.buf + self.offset; + out = @intCast(@intFromPtr(self.buf)); + out += @bitCast(@as(c_ulonglong, self.offset)); + const mem: *u8 = self.buf + self.offset; if (self.offset + size > self.size) { return 0; } self.offset += size; - _ = c.memcpy(@ptrCast(?*c_void, mem), data, @bitCast(c_ulonglong, @as(c_ulonglong, size))); - // @memcpy(@ptrCast([*]u8, @ptrCast(?*c_void, mem)), @ptrCast([*]const u8, data.?), @bitCast(c_ulonglong, @as(c_ulonglong, size))); + _ = c.memcpy(@ptrCast(mem), data, @bitCast(@as(c_ulonglong, size))); + // @memcpy(@ptrCast([*]u8, @ptrCast(?*anyopaque, mem)), @ptrCast([*]const u8, data.?), @bitCast(c_ulonglong, @as(c_ulonglong, size))); } if (self.stack != null) { @@ -164,13 +165,13 @@ pub const AtomForge = extern struct { /// Pad so next write is 64-bit aligned. pub fn pad(self: *Self, written: u32) void { const pad_: u64 = 0; - var pad_size: u32 = c.lv2_atom_pad_size(written) - written; - _ = self.raw(@ptrCast(?*const c_void, &pad_), pad_size); + const pad_size: u32 = c.lv2_atom_pad_size(written) - written; + _ = self.raw(@ptrCast(&pad_), pad_size); } /// `raw` but with padding. - pub fn write(self: *Self, data: ?*const c_void, size: u32) AtomForgeRef { - var out = self.raw(data, size); + pub fn write(self: *Self, data: ?*const anyopaque, size: u32) AtomForgeRef { + const out = self.raw(data, size); if (out != 0) { self.pad(size); } @@ -179,9 +180,9 @@ pub const AtomForge = extern struct { /// Write a null-terminated string body. pub fn stringBody(self: *Self, str: []const u8, len: u32) AtomForgeRef { - var out = self.raw(@ptrCast(?*const c_void, str), len); + var out = self.raw(@ptrCast(str), len); if (out and o: { - out = self.raw(@ptrCast(?*const c_void, ""), 1); + out = self.raw(@ptrCast(""), 1); break :o out; }) { self.pad(len + 1); @@ -194,11 +195,13 @@ pub const AtomForge = extern struct { .size = size, .kind = kind }; - return self.raw(@ptrCast(?*const c_void, &at), @truncate(u32, @sizeOf(at))); + return self.raw(@ptrCast(&at), @truncate(@sizeOf(at))); } pub fn writeAtomPrimitive(self: *Self, at: *atom.Atom) AtomForgeRef { - return if (self.topIs(self.Vector)) self.raw(@ptrCast(?*const c_void, @ptrCast([*c]const u8, @alignCast(@import("std").meta.alignment(u8), at)) + @sizeOf(atom.Atom)), at.size) else self.write(@ptrCast(?*c_void, at), @truncate(u32, @sizeOf(at)) + at.size); + const aa : [*]u8 = @ptrCast(@alignCast(at)); + const ee : u32 = @truncate(@sizeOf(at)); + return if (self.topIs(self.Vector)) self.raw( aa + @sizeOf(atom.Atom), at.size) else self.write(@ptrCast(at), ee + at.size); } fn writeAtomOfType(self: *Self, comptime T: type, value: T, kind: urid.URID) AtomForgeRef { @@ -237,10 +240,11 @@ pub const AtomForge = extern struct { } pub fn writeSequenceHead(self: *Self, frame: *AtomForgeFrame, unit: u32) AtomForgeRef { + const aa : u32 = @truncate(@sizeOf(atom.AtomSequenceBody)); var seq = atom.AtomSequence{ .atom = .{ // .size = @as(u32, @sizeOf(atom.AtomSequenceBody)), - .size = @bitCast(u32, @truncate(c_uint, @sizeOf(atom.AtomSequenceBody))), + .size = @bitCast(aa), .kind = self.Sequence }, .body = .{ @@ -248,8 +252,9 @@ pub const AtomForge = extern struct { .pad = 0 } }; - return self.push(frame, self.write(@ptrCast(?*const c_void, &seq), @bitCast(u32, @truncate(c_uint, @sizeOf(atom.AtomSequence))))); - // return self.push(frame, self.write(@ptrCast(?*const c_void, &seq), @sizeOf(atom.AtomSequence))); + const ee : u32 = @truncate(@sizeOf(atom.AtomSequence)); + return self.push(frame, self.write(@ptrCast(&seq), @bitCast(ee))); + // return self.push(frame, self.write(@ptrCast(?*const anyopaque, &seq), @sizeOf(atom.AtomSequence))); } }; diff --git a/src/c.zig b/src/c.zig index 649dd0b..a91f5aa 100644 --- a/src/c.zig +++ b/src/c.zig @@ -6,7 +6,8 @@ pub usingnamespace @cImport({ @cInclude("lv2/urid/urid.h"); @cInclude("lv2/atom/atom.h"); - @cInclude("lv2/atom/util.h"); + //@cInclude("lv2/atom/util.h"); + @cInclude("atom_util.h"); @cInclude("lv2/atom/forge.h"); @cInclude("lv2/midi/midi.h"); diff --git a/src/lv2.zig b/src/lv2.zig index 492bdfa..8a45b90 100644 --- a/src/lv2.zig +++ b/src/lv2.zig @@ -9,15 +9,19 @@ pub usingnamespace @import("atom/forge.zig"); pub usingnamespace @import("state.zig"); pub usingnamespace @import("utils.zig"); +pub const utils = @import("utils.zig"); + +//const ra = @import("random_access.zig"); + pub const Descriptor = c.LV2_Descriptor; pub fn Handlers(comptime Handle_: type) type { return struct { run: ?fn (handle: *Handle_, samples: u32) void = null, - instantiate: ?fn (handle: *Handle_, descriptor: *const Descriptor, rate: f64, bundle_path: []const u8, features: Features) anyerror!void = null, + instantiate: ?fn (handle: *Handle_, descriptor: *const Descriptor, rate: f64, bundle_path: []const u8, features: utils.Features) anyerror!void = null, activate: ?fn (handle: *Handle_) void = null, deactivate: ?fn (handle: *Handle_) void = null, - extensionData: ?fn(uri: []const u8) ?*c_void = null + extensionData: ?fn(uri: []const u8) ?*anyopaque = null }; } @@ -32,35 +36,44 @@ pub const Plugin = struct { const Handle__ = self.Handle; fn toHandle(instance: c.LV2_Handle) *Handle__ { - return @ptrCast(*Handle__, @alignCast(@alignOf(*Handle__), instance)); + return @ptrCast(@alignCast(instance)); } pub fn instantiate(descriptor: [*c]const Descriptor, rate: f64, bundle_path: [*c]const u8, features: [*c]const [*c]const c.LV2_Feature) callconv(.C) c.LV2_Handle { - var handle = std.heap.c_allocator.create(Handle__) catch { + + const handle = std.heap.c_allocator.create(Handle__) catch { std.debug.print("Yeah you're kinda screwed!", .{}); - std.os.exit(1); + @trap(); + //std.os.exit(1); }; - - if (handlers.instantiate) |act| act(handle, @ptrCast(*const Descriptor, descriptor), rate, std.mem.span(bundle_path), Features.init(@ptrCast(*const []c.LV2_Feature, features).*)) catch { + + if (handlers.instantiate) |act| { + const feats = utils.Features.init(features); + act(handle, @ptrCast(descriptor), rate, std.mem.span(bundle_path), feats) catch { std.heap.c_allocator.destroy(handle); - std.os.exit(1); - }; + @trap(); + }; + //std.os.exit(1); + } - return @ptrCast(c.LV2_Handle, handle); + return @ptrCast(handle); } pub fn cleanup(instance: c.LV2_Handle) callconv(.C) void { std.heap.c_allocator.destroy(toHandle(instance)); } - pub fn connect_port(instance: c.LV2_Handle, port: u32, data: ?*c_void) callconv(.C) void { + pub fn connect_port(instance: c.LV2_Handle, port: u32, data: ?*anyopaque) callconv(.C) void { var hnd = toHandle(instance); - inline for (std.meta.fields(@TypeOf(hnd.*))) |field, i| { + inline for (std.meta.fields(@TypeOf(hnd.*)), 0..) |field, i| { if (i == port) { - if (@typeInfo(field.field_type) != .Pointer) { - if (@hasDecl(field.field_type, "connectPort")) @field(@field(hnd, field.name), "connectPort")(data); - } else @field(hnd, field.name) = @ptrCast(field.field_type, @alignCast(@alignOf(field.field_type), data)); + if (@typeInfo(field.type) != .pointer) { + if (@hasDecl(field.type, "connectPort")) @field(@field(hnd, field.name), "connectPort")(data); + } else if (data != null) { + @field(hnd, field.name) = @ptrCast(@alignCast(data)); + std.debug.print("._. {d} {*} {*}\n", .{i, data, @field(hnd, field.name)}); + } // NOTE: if the pointer is null nothing happens } } } @@ -73,7 +86,7 @@ pub const Plugin = struct { if (handlers.deactivate) |deact| deact(toHandle(instance)); } - pub fn extension_data(uri: [*c]const u8) callconv(.C) ?*c_void { + pub fn extension_data(uri: [*c]const u8) callconv(.C) ?*anyopaque { if (handlers.extensionData) |rn| return rn(std.mem.span(uri)); return null; } @@ -89,13 +102,13 @@ pub const Plugin = struct { } }; - @export(lv.instantiate, .{ .name = "instantiate", .linkage = .Strong }); - @export(lv.connect_port, .{ .name = "connect_port", .linkage = .Strong }); - @export(lv.activate, .{ .name = "activate", .linkage = .Strong }); - @export(lv.run, .{ .name = "run", .linkage = .Strong }); - @export(lv.deactivate, .{ .name = "deactivate", .linkage = .Strong }); - @export(lv.cleanup, .{ .name = "cleanup", .linkage = .Strong }); - @export(lv.extension_data, .{ .name = "extension_data", .linkage = .Strong }); - @export(lv.lv2_descriptor, .{ .name = "lv2_descriptor", .linkage = .Strong }); + @export(&lv.instantiate, .{ .name = "instantiate", .linkage = .strong }); + @export(&lv.connect_port, .{ .name = "connect_port", .linkage = .strong }); + @export(&lv.activate, .{ .name = "activate", .linkage = .strong }); + @export(&lv.run, .{ .name = "run", .linkage = .strong }); + @export(&lv.deactivate, .{ .name = "deactivate", .linkage = .strong }); + @export(&lv.cleanup, .{ .name = "cleanup", .linkage = .strong }); + @export(&lv.extension_data, .{ .name = "extension_data", .linkage = .strong }); + @export(&lv.lv2_descriptor, .{ .name = "lv2_descriptor", .linkage = .strong }); } }; diff --git a/src/state.zig b/src/state.zig index b9d678d..eb1181c 100644 --- a/src/state.zig +++ b/src/state.zig @@ -2,7 +2,7 @@ const c = @import("c.zig"); const std = @import("std"); const lv2 = @import("lv2.zig"); -const StateStatus = extern enum(c_int) { +const StateStatus = enum(c_int) { state_success = 0, state_err_unknown = 1, state_err_bad_type = 2, @@ -16,7 +16,7 @@ const StateStatus = extern enum(c_int) { pub fn StateMap(comptime State: type) type { var fields: [std.meta.fields(State).len]std.builtin.TypeInfo.StructField = undefined; - for (std.meta.fields(State)) |field, i| { + for (std.meta.fields(State), 0..) |field, i| { fields[i] = .{ .name = field.name, .field_type = u32, @@ -37,13 +37,13 @@ pub fn StateMap(comptime State: type) type { } pub fn StateManager(comptime State: type) type { - var SM = StateMap(State); + //var SM = StateMap(State); return struct { const Self = @This(); state: State, - state_urid_map: SM, - state_type_map: SM, + state_urid_map: StateMap(State), + state_type_map: StateMap(State), pub fn map(self: *Self, comptime uri: []const u8, map_: *lv2.URIDMap) void { inline for (std.meta.fields(State)) |field| { @@ -52,21 +52,21 @@ pub fn StateManager(comptime State: type) type { } } - pub fn extensionData(uri: []const u8) ?*c_void { + pub fn extensionData(uri: []const u8) ?*anyopaque { if (std.mem.eql(u8, uri, lv2.c.LV2_STATE__interface)) { var state = lv2.c.LV2_State_Interface{ .save = Self.save, .restore = Self.restore }; - return @ptrCast(*c_void, &state); + return @ptrCast(&state); } else return null; } pub fn setParameter(self: *Self, field_urid: lv2.URID, value: *lv2.Atom) void { - inline for (std.meta.fields(SM)) |s| { + inline for (std.meta.fields(StateMap(State))) |s| { if (@field(self.state_urid_map, s.name) == field_urid) { const to = *@TypeOf(@field(self.state, s.name)); - @field(self.state, s.name) = @ptrCast(to, @alignCast(@alignOf(to), value)).*; + @field(self.state, s.name) = @as(to, @alignCast(value)).*; return; } } @@ -79,22 +79,27 @@ pub fn StateManager(comptime State: type) type { // but also internally for writing messages in the audio thread by passing a // "store" function which actually writes the description to the forge. pub fn save (handle: lv2.c.LV2_Handle, store: lv2.c.LV2_State_Store_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { - if (store == null) return @intToEnum(lv2.c.LV2_State_Status, 0); + if (store == null) return @enumFromInt(0); - var state = @ptrCast(*State, @alignCast(@alignOf(*State), state_handle)); - var map_path = lv2.getFeatureData(@ptrCast(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; + const state = @as(*State, @alignCast(state_handle)); + //var map_path = lv2.getFeatureData(@as(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; - var status = @intToEnum(lv2.c.LV2_State_Status, 0); + _ = flags; + _ = features; + + var status = @as(lv2.c.LV2_State_Status, 0); inline for (std.meta.fields(State)) |field| { var value = @field(state, field.name); + const state_parent_ptr : *Self = @fieldParentPtr("state", state); + status = store.?( handle, - @field(@fieldParentPtr(Self, "state", state).state_urid_map, field.name), - @intToPtr(*lv2.Atom, @ptrToInt(&value) + @sizeOf(lv2.Atom)), + @field(state_parent_ptr.state_urid_map, field.name), + @ptrFromInt(@intFromPtr(&value) + @sizeOf(lv2.Atom)), value.atom.size, - @field(@fieldParentPtr(Self, "state", state).state_type_map, field.name), lv2.c.LV2_STATE_IS_POD | lv2.c.LV2_STATE_IS_PORTABLE + @field(state_parent_ptr.state_type_map, field.name), lv2.c.LV2_STATE_IS_POD | lv2.c.LV2_STATE_IS_PORTABLE ); } @@ -102,20 +107,25 @@ pub fn StateManager(comptime State: type) type { } pub fn restore (handle: lv2.c.LV2_Handle, retrieve: lv2.c.LV2_State_Retrieve_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { - var state = @ptrCast(*State, @alignCast(@alignOf(*State), state_handle)); - var map_path = lv2.getFeatureData(@ptrCast(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; - var status = @intToEnum(lv2.c.LV2_State_Status, 0); - + const state = @as(*State, @alignCast(state_handle)); + //var map_path = lv2.getFeatureData(@as(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; + var status : lv2.c.LV2_State_Status = @enumFromInt( 0); + + _ = flags; + _ = features; + + const state_parent_ptr : *Self = @fieldParentPtr("state", state); + inline for (std.meta.fields(State)) |field| { - var key = @field(@fieldParentPtr(Self, "state", state).state_urid_map, field.name); + const key = @field(state_parent_ptr.state_urid_map, field.name); var vsize: usize = 0; var vtype: u32 = 0; var vflags: u32 = 0; if (retrieve.?(handle, key, &vsize, &vtype, &vflags)) |v| - {} - else status = @intToEnum(lv2.c.LV2_State_Status, 4); + { _ = v;} + else status = @enumFromInt(4); } return status; diff --git a/src/urid.zig b/src/urid.zig index 5c10c4e..fad61ee 100644 --- a/src/urid.zig +++ b/src/urid.zig @@ -2,17 +2,17 @@ const c = @import("c.zig"); pub const URID = u32; -pub const MapHandle = ?*c_void; -pub const UnmapHandle = ?*c_void; +pub const MapHandle = ?*anyopaque; +pub const UnmapHandle = ?*anyopaque; pub const URIDMap = extern struct { const Self = @This(); handle: MapHandle, - map_: ?fn (MapHandle, [*c]const u8) callconv(.C) URID, + map_: ?*const fn (MapHandle, [*c]const u8) callconv(.C) URID, - pub fn fromData(data: *c_void) *Self { - return @ptrCast(*Self, @alignCast(@alignOf(*Self), data)); + pub fn fromData(data: *anyopaque) *Self { + return @ptrCast(@alignCast(data)); } pub fn toURI() []const u8 { @@ -20,7 +20,7 @@ pub const URIDMap = extern struct { } pub fn map(self: Self, uri: []const u8) u32 { - return self.map_.?(self.handle, @ptrCast([*c]const u8, uri)); + return self.map_.?(self.handle, @ptrCast(uri)); } }; @@ -30,8 +30,8 @@ pub const URIDUnmap = extern struct { handle: UnmapHandle, unmap_: ?fn (UnmapHandle, URID) callconv(.C) [*c]const u8, - pub fn fromData(data: *c_void) *Self { - return @ptrCast(*Self, @alignCast(@alignOf(*Self), data)); + pub fn fromData(data: *anyopaque) *Self { + return @ptrCast(@alignCast(data)); } pub fn toURI() []const u8 { diff --git a/src/utils.zig b/src/utils.zig index ac4d612..e67ff32 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -4,19 +4,21 @@ const std = @import("std"); pub const Logger = struct { logger_internal: c.LV2_Log_Logger, - pub fn applyData(self: @This(), data: *c_void) void { - self.logger_internal.log = @ptrCast(*c.LV2_Log_Log, data); + pub fn applyData(self: @This(), data: *anyopaque) void { + self.logger_internal.log = @ptrCast(data); } }; pub const Features = struct { const Self = @This(); - features: []const c.LV2_Feature, + //features: []const c.LV2_Feature, + features: [*:null]const? *const c.LV2_Feature, - pub fn init(features: []const c.LV2_Feature) Self { + pub fn init(features: [*c]const [*c]const c.LV2_Feature) Self { return Self{ - .features = features + //.features = @as(*const[]c.LV2_Feature, @ptrCast(features)).* + .features = @ptrCast(features) }; } @@ -25,16 +27,27 @@ pub const Features = struct { } }; -pub fn getFeatureData(features: []const c.LV2_Feature, uri: []const u8) ?*c_void { - for (features) |filled_feat| { - if (filled_feat.URI != null and std.mem.eql(u8, uri, std.mem.span(filled_feat.URI))) { - if (filled_feat.data) |dd| return dd; +pub fn getFeatureData(features: [*:null]const? *const c.LV2_Feature, uri: []const u8) ?*anyopaque { + + //for (features) |filled_feat| { + //if (filled_feat.URI != null and std.mem.eql(u8, uri, std.mem.span(filled_feat.URI))) { + //if (filled_feat.data) |dd| return dd; + //} + //} + + var idx : usize = 0; + while( features[idx] != null ) { + if (features[idx]) |filled_feat| { + if (filled_feat.*.URI != null and std.mem.eql(u8, uri, std.mem.span(filled_feat.*.URI))) { + if (filled_feat.*.data) |dd| return dd; + } } + idx += 1; } return null; } -pub fn queryFeature(features: []const c.LV2_Feature, comptime T: type) ?*T { +pub fn queryFeature(features: [*:null]const? *const c.LV2_Feature, comptime T: type) ?*T { return @field(T, "fromData")(getFeatureData(features, @field(T, "toURI")()) orelse return null); } From 0dc35d2d11ef706bc375afe1a4193dce8f37fd52 Mon Sep 17 00:00:00 2001 From: esteban Date: Thu, 7 Aug 2025 00:37:30 +0200 Subject: [PATCH 5/9] WIP: params' spring parameter works --- examples/params/params.ttl | 34 +++++----- examples/params/params.zig | 127 +++++++++++++++++++++++-------------- src/atom/atom.zig | 15 ++++- src/atom/forge.zig | 102 ++++++++++++++++++++++------- src/lv2.zig | 1 - src/state.zig | 82 ++++++++++++++---------- src/urid.zig | 2 +- 7 files changed, 238 insertions(+), 125 deletions(-) diff --git a/examples/params/params.ttl b/examples/params/params.ttl index ba54712..b0bae9a 100644 --- a/examples/params/params.ttl +++ b/examples/params/params.ttl @@ -3,7 +3,7 @@ @prefix lv2: . @prefix param: . @prefix patch: . -@prefix plug: . +@prefix plug: . @prefix rdfs: . @prefix state: . @prefix urid: . @@ -69,7 +69,7 @@ plug:spring a lv2:Plugin , lv2:UtilityPlugin ; - lv2:binary ; + lv2:binary ; doap:name "Params" ; doap:license ; @@ -100,13 +100,13 @@ plug:spring ] ; # The plugin must list all parameters that can be written (e.g. changed by the # user) as patch:writable: - patch:writable plug:int , - plug:long , - plug:float , - plug:double , - plug:bool , - plug:string , - plug:path , + patch:writable plug:aint , + plug:along , + plug:afloat , + plug:adouble , + plug:abool , + plug:astring , + plug:apath , plug:spring ; # Similarly, parameters that may change internally must be listed as patch:readable, # meaning to host should watch for changes to the parameter's value: @@ -117,13 +117,13 @@ plug:spring # state:loadDefaultState feature (required above) requires that the host loads # the default state after instantiation but before running the plugin. state:state [ - plug:int 0 ; - plug:long "0"^^xsd:long ; - plug:float "0.1234"^^xsd:float ; - plug:double "0e0"^^xsd:double ; - plug:bool false ; - plug:string "Hello, world" ; - plug:path ; + plug:aint 0 ; + plug:along "0"^^xsd:long ; + plug:afloat "0.1234"^^xsd:float ; + plug:adouble "0e0"^^xsd:double ; + plug:abool false ; + plug:astring "Hello, world" ; + plug:apath ; plug:spring "0.0"^^xsd:float ; plug:lfo "0.0"^^xsd:float - ] . \ No newline at end of file + ] . diff --git a/examples/params/params.zig b/examples/params/params.zig index e433fe3..c6c75dc 100644 --- a/examples/params/params.zig +++ b/examples/params/params.zig @@ -7,6 +7,7 @@ pub const URIs = struct { atom_sequence: u32, atom_urid: u32, atom_event_transfer: u32, + state_changed: u32, midi_event: u32, patch_set: u32, patch_subject: u32, @@ -19,6 +20,7 @@ pub const URIs = struct { self.atom_sequence = map_.map(lv2.c.LV2_ATOM__Sequence); self.atom_urid = map_.map(lv2.c.LV2_ATOM__URID); self.atom_event_transfer = map_.map(lv2.c.LV2_ATOM__eventTransfer); + self.state_changed = map_.map(lv2.c.LV2_STATE__StateChanged); self.midi_event = map_.map(lv2.c.LV2_MIDI__MidiEvent); self.patch_set = map_.map(lv2.c.LV2_PATCH__Set); self.patch_subject = map_.map(lv2.c.LV2_PATCH__subject); @@ -27,17 +29,20 @@ pub const URIs = struct { } }; -pub const StateManager = lv2.StateManager(struct { - aint: lv2.AtomInt, - along: lv2.AtomLong, - afloat: lv2.AtomFloat, - adouble: lv2.AtomDouble, - abool: lv2.AtomBool, - astring: lv2.AtomString, - apath: lv2.AtomPath, - lfo: lv2.AtomFloat, - spring: lv2.AtomFloat -}); +pub const StateManager = lv2.StateManager( + struct { + aint: lv2.AtomInt, + along: lv2.AtomLong, + afloat: lv2.AtomFloat, + adouble: lv2.AtomDouble, + abool: lv2.AtomBool, + astring: lv2.AtomString(1024), + apath: lv2.AtomPath(1024), + lfo: lv2.AtomFloat, + spring: lv2.AtomFloat + }, + Params.Handle +); pub const Params = lv2.Plugin{ .uri = "http://augustera.me/params", @@ -55,7 +60,9 @@ pub const Params = lv2.Plugin{ uris: URIs, // State - state_manager: StateManager + state_manager: StateManager, + + //out_frame : lv2.AtomForgeFrame }, }; @@ -76,6 +83,10 @@ fn instantiate ( bundle_path: []const u8, features: lv2.Features ) anyerror!void { + _ = descriptor; + _ = rate; + _ = bundle_path; + handle.map = features.query(lv2.URIDMap).?; handle.unmap = features.query(lv2.URIDUnmap).?; handle.forge.init(handle.map); @@ -85,63 +96,85 @@ fn instantiate ( } fn activate(handle: *Params.Handle) void { + _ = handle; } fn deactivate(handle: *Params.Handle) void { // debug_file.close(); + _ = handle; } fn log(comptime f: []const u8, a: anytype) void { - var debug_file = std.fs.cwd().createFile("C:/Programming/Zig/zig-lv2/log.b", .{}) catch {std.os.exit(1);}; + var debug_file = std.fs.cwd().createFile("C:/Programming/Zig/zig-lv2/log.b", .{}) catch {std.process.exit(1);}; debug_file.writer().print(f, a) catch {}; } fn run(handle: *Params.Handle, samples: u32) void { - handle.forge.setBuffer(handle.out.toBuffer(), handle.out.atom.size); - - var out_frame = std.mem.zeroes(lv2.AtomForgeFrame); - _ = handle.forge.writeSequenceHead(&out_frame, 0); + _ = samples; + // TODO: + // in eg-params, the input event loop handles patch_get events that emit the value of the object and puts them somewhere, as generic values? as setting other properties? + // the spring thing emmits patch_set events with its value all the way down + + // handle input events var iter = handle.in.iterator(); while (iter.next()) |event| { - @panic("B"); - // var obj = event.toAtomObject(); - // if (obj.body.kind == handle.uris.patch_set) { - // var subject: ?*lv2.AtomURID = null; - // var property: ?*lv2.AtomURID = null; - // var value: ?*lv2.Atom = null; - - // obj.query(&[_]lv2.AtomObjectQuery{ - // .{ .key = handle.uris.patch_subject, .value = @ptrCast(*?*lv2.Atom, &subject) }, - // .{ .key = handle.uris.patch_property, .value = @ptrCast(*?*lv2.Atom, &property) }, - // .{ .key = handle.uris.patch_value, .value = &value } - // }); - - // handle.state_manager.setParameter(property.?.body, value.?); - // } + var obj = event.toAtomObject(); + if (obj.body.kind == handle.uris.patch_set) { + var subject: ?*lv2.AtomURID = null; + var property: ?*lv2.AtomURID = null; + var value: ?*lv2.Atom = null; + + obj.query(&[_]lv2.AtomObjectQuery{ + .{ .key = handle.uris.patch_subject, .value = @ptrCast(&subject) }, + .{ .key = handle.uris.patch_property, .value = @ptrCast(&property) }, + .{ .key = handle.uris.patch_value, .value = &value } + }); + + handle.state_manager.setParameter(property.?.body, value.?); + } else { + std.debug.print("run() TODO: handle event kind {}\n", .{obj.body.kind}); + } + } + + const out_size = handle.out.atom.size; + handle.forge.setBuffer(handle.out.toBuffer(), out_size); + + var out_frame : lv2.AtomForgeFrame = std.mem.zeroes(lv2.AtomForgeFrame); + _ = handle.forge.writeSequenceHead(&out_frame, 0); + + if ( handle.state_manager.state.spring.body > 0.0 ) { + + if ( handle.state_manager.state.spring.body >= 0.001 ) { + handle.state_manager.state.spring.body -= 0.001; + } else { + handle.state_manager.state.spring.body = 0.0; + } + + // spring value patch set event + + _ = handle.forge.writeFrameTime(0); + var spring_frame : lv2.AtomForgeFrame = std.mem.zeroes(lv2.AtomForgeFrame); + _ = handle.forge.writeObject(&spring_frame, 0, handle.uris.patch_set); + _ = handle.forge.writeKey(handle.uris.patch_property); + _ = handle.forge.writeAtomURID(handle.state_manager.state_urid_map.spring); + _ = handle.forge.writeKey(handle.uris.patch_value); + _ = handle.forge.writeAtomFloat(handle.state_manager.state.spring.body); + handle.forge.pop(&spring_frame); } handle.forge.pop(&out_frame); - // @panic("Empty"); } -fn extensionData(uri: []const u8) ?*c_void { +fn extensionData(uri: []const u8) ?*anyopaque { if (StateManager.extensionData(uri)) |ext| return ext; return null; } -pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) noreturn { - var debug_file = std.fs.cwd().createFile("C:/Programming/Zig/zig-lv2/log.a", .{}) catch {std.os.exit(1);}; - debug_file.writer().writeAll(msg) catch {}; - - const debug_info = std.debug.getSelfDebugInfo() catch |err| { - debug_file.writer().print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch std.process.exit(1); - std.process.exit(1); - }; - std.debug.writeCurrentStackTrace(debug_file.writer(), std.debug.getSelfDebugInfo() catch std.os.exit(1), std.debug.detectTTYConfig(), @returnAddress()) catch |err| { - debug_file.writer().print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch std.process.exit(1); - std.process.exit(1); - }; - +pub const panic = std.debug.FullPanic(myPanic); + +fn myPanic(msg: []const u8, first_trace_addr: ?usize) noreturn { + _ = first_trace_addr; + std.debug.print("Panic! {s}\n", .{msg}); std.process.exit(1); } diff --git a/src/atom/atom.zig b/src/atom/atom.zig index 65a0bcf..bc75bdd 100644 --- a/src/atom/atom.zig +++ b/src/atom/atom.zig @@ -41,7 +41,7 @@ pub const AtomObject = extern struct { return AtomObjectIterator.init(@ptrCast(self)); } - pub fn query(self: *Self, queries: []AtomObjectQuery) void { + pub fn query(self: *Self, queries: [] const AtomObjectQuery) void { var it = self.iterator(); while (it.next()) |prop| { for (queries) |q| { @@ -164,5 +164,14 @@ pub const AtomFloat = AtomOf(f32, c.LV2_ATOM__Float); pub const AtomDouble = AtomOf(f64, c.LV2_ATOM__Double); pub const AtomBool = AtomOf(bool, c.LV2_ATOM__Bool); pub const AtomURID = AtomOf(u32, c.LV2_ATOM__URID); -pub const AtomString = AtomOf([*:0]const u8, c.LV2_ATOM__String); -pub const AtomPath = AtomOf([*:0]const u8, c.LV2_ATOM__Path); + +//pub const AtomString = AtomOf([*:0]const u8, c.LV2_ATOM__String); +//pub const AtomPath = AtomOf([*:0]const u8, c.LV2_ATOM__Path); + +pub fn AtomString(comptime N: usize) type { + return AtomOf([N:0]u8, c.LV2_ATOM__String); +} + +pub fn AtomPath(comptime N: usize) type { + return AtomOf([N:0]u8, c.LV2_ATOM__Path); +} diff --git a/src/atom/forge.zig b/src/atom/forge.zig index 0e15a63..fc272ee 100644 --- a/src/atom/forge.zig +++ b/src/atom/forge.zig @@ -5,11 +5,11 @@ const urid = @import("../urid.zig"); pub const AtomForgeSinkHandle = ?*anyopaque; pub const AtomForgeRef = isize; -pub const AtomForgeSink = ?fn (sink_handle: AtomForgeSinkHandle, buf: ?*const anyopaque, size: u32) callconv(.C) AtomForgeRef; -pub const AtomForgeDerefFunc = ?fn (sink_handle: AtomForgeSinkHandle, ref: AtomForgeRef) callconv(.C) [*c]atom.Atom; +pub const AtomForgeSink = ?*fn (sink_handle: AtomForgeSinkHandle, buf: ?*const anyopaque, size: u32) callconv(.C) AtomForgeRef; +pub const AtomForgeDerefFunc = ?*fn (sink_handle: AtomForgeSinkHandle, ref: AtomForgeRef) callconv(.C) [*c]atom.Atom; pub const AtomForgeFrame = extern struct { - parent: [*c]AtomForgeFrame, + parent: ?*AtomForgeFrame, ref: AtomForgeRef }; @@ -25,7 +25,7 @@ pub const AtomForge = extern struct { deref_func: AtomForgeDerefFunc, /// The handle to the output sink. sink_handle: AtomForgeSinkHandle, - stack: [*c]AtomForgeFrame, + stack: ?*AtomForgeFrame, /// Deprecated Blank: urid.URID, @@ -70,11 +70,11 @@ pub const AtomForge = extern struct { self.URID = map.map(c.LV2_ATOM__URID); self.Vector = map.map(c.LV2_ATOM__Vector); } - + /// Access the Atom pointed to by a reference. pub fn deref(self: *Self, ref: AtomForgeRef) *atom.Atom { if (ref < 0) @panic("huh"); - return if (self.buf != null) @ptrFromInt(std.math.absCast(ref)) else self.deref_func.?(self.sink_handle, ref); + return if (self.buf != null) @ptrFromInt(@abs(ref)) else self.deref_func.?(self.sink_handle, ref); } /// Push a stack frame. Automatically handled by container functions. @@ -99,10 +99,12 @@ pub const AtomForge = extern struct { /// Return true if the top of the stack is the given kind. pub fn topIs(self: *Self, kind: urid.URID) bool { - return - self.stack != null and - self.stack.ref != 0 and - self.deref(self.stack.ref).kind == kind; + if (self.stack) |st| { + if ( st.ref != 0 ) { + return self.deref(st.ref).kind == kind; + } + } + return false; } /// Return true if `kind` is an atom:Object @@ -155,10 +157,19 @@ pub const AtomForge = extern struct { // @memcpy(@ptrCast([*]u8, @ptrCast(?*anyopaque, mem)), @ptrCast([*]const u8, data.?), @bitCast(c_ulonglong, @as(c_ulonglong, size))); } - if (self.stack != null) { - self.deref(self.stack.*.parent.*.ref).size += size; + //if (self.stack != null) { + //self.deref(self.stack.*.parent.*.ref).size += size; + //} + //for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) { + // lv2_atom_forge_deref(forge, f->ref)->size += size; + //} + + var f = self.stack; + while (f) |ff| { + self.deref(ff.ref).size += size; + f = ff.parent; } - + return out; } @@ -170,6 +181,9 @@ pub const AtomForge = extern struct { } /// `raw` but with padding. + /// port of lv2_atom_forge_write() + /// static inline LV2_Atom_Forge_Ref + /// lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size) pub fn write(self: *Self, data: ?*const anyopaque, size: u32) AtomForgeRef { const out = self.raw(data, size); if (out != 0) { @@ -200,14 +214,14 @@ pub const AtomForge = extern struct { pub fn writeAtomPrimitive(self: *Self, at: *atom.Atom) AtomForgeRef { const aa : [*]u8 = @ptrCast(@alignCast(at)); - const ee : u32 = @truncate(@sizeOf(at)); + const ee : u32 = @truncate(@sizeOf(atom.Atom)); return if (self.topIs(self.Vector)) self.raw( aa + @sizeOf(atom.Atom), at.size) else self.write(@ptrCast(at), ee + at.size); } - fn writeAtomOfType(self: *Self, comptime T: type, value: T, kind: urid.URID) AtomForgeRef { - var at = atom.AtomInt{ + fn writeAtomOfType(self: *Self, comptime T: type, comptime atomType: type, value: T, kind: urid.URID) AtomForgeRef { + var at = atomType{ .atom = .{ - .size = @sizeOf(value), + .size = @sizeOf(T), .kind = kind }, .body = value @@ -216,27 +230,27 @@ pub const AtomForge = extern struct { } pub fn writeAtomInt(self: *Self, value: i32) AtomForgeRef { - return self.writeAtomOfType(i32, value, self.Int); + return self.writeAtomOfType(i32, atom.AtomInt, value, self.Int); } pub fn writeAtomLong(self: *Self, value: i64) AtomForgeRef { - return self.writeAtomOfType(i64, value, self.Long); + return self.writeAtomOfType(i64, atom.AtomLong, value, self.Long); } pub fn writeAtomFloat(self: *Self, value: f32) AtomForgeRef { - return self.writeAtomOfType(f32, value, self.Float); + return self.writeAtomOfType(f32, atom.AtomFloat, value, self.Float); } pub fn writeAtomDouble(self: *Self, value: f64) AtomForgeRef { - return self.writeAtomOfType(f64, value, self.Double); + return self.writeAtomOfType(f64, atom.AtomDouble, value, self.Double); } pub fn writeAtomBool(self: *Self, value: bool) AtomForgeRef { - return self.writeAtomOfType(bool, value, self.Bool); + return self.writeAtomOfType(bool, atom.AtomBool, value, self.Bool); } pub fn writeAtomURID(self: *Self, value: urid.URID) AtomForgeRef { - return self.writeAtomOfType(urid.URID, value, self.URID); + return self.writeAtomOfType(urid.URID, atom.AtomURID, value, self.URID); } pub fn writeSequenceHead(self: *Self, frame: *AtomForgeFrame, unit: u32) AtomForgeRef { @@ -256,6 +270,48 @@ pub const AtomForge = extern struct { return self.push(frame, self.write(@ptrCast(&seq), @bitCast(ee))); // return self.push(frame, self.write(@ptrCast(?*const anyopaque, &seq), @sizeOf(atom.AtomSequence))); } + + // port of: + // static inline LV2_Atom_Forge_Ref + // lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) + pub fn writeFrameTime(self: *Self, frames: i64) AtomForgeRef { + return self.write(&frames, @sizeOf(i64)); + } + + + // port of: + // static inline LV2_Atom_Forge_Ref + // lv2_atom_forge_object(LV2_Atom_Forge* forge, + // LV2_Atom_Forge_Frame* frame, + // LV2_URID id, + // LV2_URID otype) + pub fn writeObject(self: *Self, frame: *AtomForgeFrame, id: urid.URID, otype: urid.URID) AtomForgeRef { + const aa : u32 = @truncate(@sizeOf(atom.AtomObject)); + var oo = atom.AtomObject{ + .atom = .{ + .size = @bitCast(aa), + .kind = self.Object + }, + .body = .{ + .id = id, + .kind = otype + } + }; + const ee : u32 = @truncate(@sizeOf(atom.AtomObject)); + return self.push(frame, self.write(@ptrCast(&oo), @bitCast(ee))); + } + + // port of: + // static inline LV2_Atom_Forge_Ref + // lv2_atom_forge_key(LV2_Atom_Forge* forge, LV2_URID key) + pub fn writeKey(self: *Self, key : urid.URID) AtomForgeRef { + var oo = atom.AtomPropertyBody{ + .key = key, + .context = 0, + .value = atom.Atom{ .size = 0, .kind = 0,} + }; + return self.write(&oo, 2*@sizeOf(u32)); + } }; diff --git a/src/lv2.zig b/src/lv2.zig index 8a45b90..53b5978 100644 --- a/src/lv2.zig +++ b/src/lv2.zig @@ -72,7 +72,6 @@ pub const Plugin = struct { if (@hasDecl(field.type, "connectPort")) @field(@field(hnd, field.name), "connectPort")(data); } else if (data != null) { @field(hnd, field.name) = @ptrCast(@alignCast(data)); - std.debug.print("._. {d} {*} {*}\n", .{i, data, @field(hnd, field.name)}); } // NOTE: if the pointer is null nothing happens } } diff --git a/src/state.zig b/src/state.zig index eb1181c..1927d6f 100644 --- a/src/state.zig +++ b/src/state.zig @@ -1,4 +1,3 @@ -const c = @import("c.zig"); const std = @import("std"); const lv2 = @import("lv2.zig"); @@ -14,29 +13,29 @@ const StateStatus = enum(c_int) { }; pub fn StateMap(comptime State: type) type { - var fields: [std.meta.fields(State).len]std.builtin.TypeInfo.StructField = undefined; - + var fields: [std.meta.fields(State).len]std.builtin.Type.StructField = undefined; + for (std.meta.fields(State), 0..) |field, i| { fields[i] = .{ .name = field.name, - .field_type = u32, - .default_value = null, + .type = u32, + .default_value_ptr = null, .is_comptime = false, .alignment = @alignOf(u32), }; } return @Type(.{ - .Struct = .{ - .layout = .Auto, + .@"struct" = .{ + .layout = .auto, .fields = &fields, - .decls = &[_]std.builtin.TypeInfo.Declaration{}, + .decls = &[_]std.builtin.Type.Declaration{}, .is_tuple = false, } }); } -pub fn StateManager(comptime State: type) type { +pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { //var SM = StateMap(State); return struct { const Self = @This(); @@ -46,31 +45,39 @@ pub fn StateManager(comptime State: type) type { state_type_map: StateMap(State), pub fn map(self: *Self, comptime uri: []const u8, map_: *lv2.URIDMap) void { + inline for (std.meta.fields(State)) |field| { @field(self.state_urid_map, field.name) = map_.map(uri ++ "#" ++ field.name); - @field(self.state_type_map, field.name) = map_.map(field.field_type.__atom_type); + @field(self.state_type_map, field.name) = map_.map(field.type.__atom_type); } } pub fn extensionData(uri: []const u8) ?*anyopaque { if (std.mem.eql(u8, uri, lv2.c.LV2_STATE__interface)) { - var state = lv2.c.LV2_State_Interface{ - .save = Self.save, - .restore = Self.restore + const S = struct { + var iface = lv2.c.LV2_State_Interface{ + .save = Self.save, + .restore = Self.restore + }; }; - return @ptrCast(&state); + //Self.iface.save = Self.save; + //Self.iface.restore = Self.restore; + //var state = lv2.c.LV2_State_Interface{ + //.save = Self.save, + //.restore = Self.restore + //}; + return @ptrCast(&(S.iface)); } else return null; } - + pub fn setParameter(self: *Self, field_urid: lv2.URID, value: *lv2.Atom) void { inline for (std.meta.fields(StateMap(State))) |s| { if (@field(self.state_urid_map, s.name) == field_urid) { const to = *@TypeOf(@field(self.state, s.name)); - @field(self.state, s.name) = @as(to, @alignCast(value)).*; + @field(self.state, s.name) = @as(to, @ptrCast(@alignCast(value))).*; return; } } - @panic("Bad!!!"); } @@ -79,9 +86,10 @@ pub fn StateManager(comptime State: type) type { // but also internally for writing messages in the audio thread by passing a // "store" function which actually writes the description to the forge. pub fn save (handle: lv2.c.LV2_Handle, store: lv2.c.LV2_State_Store_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { - if (store == null) return @enumFromInt(0); + if (store == null) return 0; - const state = @as(*State, @alignCast(state_handle)); + const plug_ptr : *PluginHandle = @ptrCast(@alignCast(handle)); + const state_parent_ptr : *Self = &(plug_ptr.*.state_manager); //var map_path = lv2.getFeatureData(@as(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; _ = flags; @@ -90,16 +98,17 @@ pub fn StateManager(comptime State: type) type { var status = @as(lv2.c.LV2_State_Status, 0); inline for (std.meta.fields(State)) |field| { - var value = @field(state, field.name); - - const state_parent_ptr : *Self = @fieldParentPtr("state", state); + const key = @field(state_parent_ptr.state_urid_map, field.name); + const kind = @field(state_parent_ptr.state_type_map, field.name); + var value = @field(state_parent_ptr.state, field.name); status = store.?( - handle, - @field(state_parent_ptr.state_urid_map, field.name), + state_handle, + key, @ptrFromInt(@intFromPtr(&value) + @sizeOf(lv2.Atom)), value.atom.size, - @field(state_parent_ptr.state_type_map, field.name), lv2.c.LV2_STATE_IS_POD | lv2.c.LV2_STATE_IS_PORTABLE + kind, + lv2.c.LV2_STATE_IS_POD | lv2.c.LV2_STATE_IS_PORTABLE ); } @@ -107,25 +116,32 @@ pub fn StateManager(comptime State: type) type { } pub fn restore (handle: lv2.c.LV2_Handle, retrieve: lv2.c.LV2_State_Retrieve_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { - const state = @as(*State, @alignCast(state_handle)); - //var map_path = lv2.getFeatureData(@as(*const []lv2.c.LV2_Feature, features).*, lv2.c.LV2_STATE__mapPath).?; - var status : lv2.c.LV2_State_Status = @enumFromInt( 0); + const plug_ptr : *PluginHandle = @ptrCast(@alignCast(handle)); + const state_parent_ptr : *Self = &(plug_ptr.*.state_manager); + + var status : lv2.c.LV2_State_Status = 0; _ = flags; _ = features; - const state_parent_ptr : *Self = @fieldParentPtr("state", state); - inline for (std.meta.fields(State)) |field| { const key = @field(state_parent_ptr.state_urid_map, field.name); + const field_name = field.name; + _ = field_name; + var vsize: usize = 0; var vtype: u32 = 0; var vflags: u32 = 0; - if (retrieve.?(handle, key, &vsize, &vtype, &vflags)) |v| - { _ = v;} - else status = @enumFromInt(4); + if (retrieve.?(state_handle, key, &vsize, &vtype, &vflags)) |v| { + const to = @TypeOf(@field(state_parent_ptr.state, field.name).body); + const atm : *const to = @ptrCast(@alignCast(v)); + @field(state_parent_ptr.state, field.name).body = atm.*; + @field(state_parent_ptr.state, field.name).atom.size = std.math.cast(lv2.URID, vsize) orelse 0; + @field(state_parent_ptr.state, field.name).atom.kind = vtype; + } + else status = 4; } return status; diff --git a/src/urid.zig b/src/urid.zig index fad61ee..bada117 100644 --- a/src/urid.zig +++ b/src/urid.zig @@ -28,7 +28,7 @@ pub const URIDUnmap = extern struct { const Self = @This(); handle: UnmapHandle, - unmap_: ?fn (UnmapHandle, URID) callconv(.C) [*c]const u8, + unmap_: ?*fn (UnmapHandle, URID) callconv(.C) [*c]const u8, pub fn fromData(data: *anyopaque) *Self { return @ptrCast(@alignCast(data)); From e4407d029e3cf03c753e93a57d6992f812de8b00 Mon Sep 17 00:00:00 2001 From: esteban Date: Sun, 10 Aug 2025 00:16:38 +0200 Subject: [PATCH 6/9] WIP: bump lv2 version --- build.zig | 61 +++++++++++++++++++++++++-------------------- build.zig.zon | 4 ++- ext_lv2/atom_util.h | 2 +- lv2 | 2 +- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/build.zig b/build.zig index 50f3292..b4fa813 100644 --- a/build.zig +++ b/build.zig @@ -1,50 +1,49 @@ const std = @import("std"); const examples = &[_][]const u8{"amp", "fifths", "params"}; -//const examples = &[_][]const u8{"amp", "fifths"}; -//const examples = &[_][]const u8{"amp"}; pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); - // Library module - const lib_mod = b.createModule(.{ + // Module + //const mod = b.createModule(.{ + //.root_source_file = b.path("src/lv2.zig"), + //.target = target, + //.optimize = optimize, + //}); + const mod = b.addModule("lv2", .{ .root_source_file = b.path("src/lv2.zig"), .target = target, .optimize = optimize, }); - //const ext_lv2 = b.dependency("ext_lv2", .{}); - lib_mod.addCSourceFile(.{ + mod.addCSourceFile(.{ .file = b.path("ext_lv2/atom_util.c") }); - // Library - const lib = b.addLibrary(.{ - .linkage = .static, + // Library + const lib = b.addStaticLibrary(.{ .name = "lv2", - .root_module = lib_mod, + .root_module = mod, }); - // Link lv2 library - lib.linkLibC(); - lib.addIncludePath(b.path("lv2")); - lib.addIncludePath(b.path("ext_lv2")); + lib.linkLibC(); + lib.addIncludePath(b.path("lv2")); + lib.addIncludePath(b.path("ext_lv2")); + b.installArtifact(lib); - // Unit tests for library - const lib_unit_tests = b.addTest(.{ - .root_module = lib_mod, - }); - - - const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); - - // Test step - const test_step = b.step("test", "Run unit tests"); - test_step.dependOn(&run_lib_unit_tests.step); + // // Unit tests for library + // const lib_unit_tests = b.addTest(.{ + // .root_module = mod, + // }); + // const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests); + // // Test step + // const test_step = b.step("test", "Run unit tests"); + // test_step.dependOn(&run_lib_unit_tests.step); // Example generate step const examples_step = b.step("examples", "Build examples"); + inline for (examples) |example| { const source = b.path("examples/" ++ example ++ "/" ++ example ++ ".ttl"); const dest = example ++ ".lv2/manifest.ttl"; @@ -58,7 +57,15 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, .version = .{ .major = 0, .minor = 0, .patch = 2 }, }); - dll.root_module.addImport("lv2", lib_mod); - b.installArtifact(dll); + dll.root_module.addImport("lv2", mod); + + const install_example_lib = b.addInstallArtifact(dll, .{ + .dest_dir = .{ + .override = .{ + .custom = example ++ ".lv2", + } + } + }); + examples_step.dependOn(&install_example_lib.step); } } diff --git a/build.zig.zon b/build.zig.zon index d978546..234327c 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,7 +6,7 @@ // // It is redundant to include "zig" in this name because it is already // within the Zig package namespace. - .name = .lv2, + .name = "lv2", // This is a [Semantic Version](https://semver.org/). // In a future version of Zig it will be used for package deduplication. @@ -71,5 +71,7 @@ "build.zig", "build.zig.zon", "src", + "ext_lv2", + "lv2", }, } diff --git a/ext_lv2/atom_util.h b/ext_lv2/atom_util.h index 447a0c1..e9211e4 100644 --- a/ext_lv2/atom_util.h +++ b/ext_lv2/atom_util.h @@ -1,7 +1,7 @@ #ifndef ATOM_UTIL_H #define ATOM_UTIL_H -#include "../lv2/lv2/atom/util.h" +#include "../lv2/include/lv2/atom/util.h" LV2_Atom_Event* ext_lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body); diff --git a/lv2 b/lv2 index 611759d..93db9d7 160000 --- a/lv2 +++ b/lv2 @@ -1 +1 @@ -Subproject commit 611759daacc377a2dba97723097338fceffd6ef8 +Subproject commit 93db9d7b61737726747b81a586f807f9faa60a5c From 468e9ff35c8ae09630cb5ce2334876120cf75011 Mon Sep 17 00:00:00 2001 From: esteban Date: Sun, 10 Aug 2025 00:36:00 +0200 Subject: [PATCH 7/9] WIP: added build.zig files to the examples. Added instructions in README.md --- README.md | 18 ++++++++++++++++ build.zig | 4 ++-- build.zig.zon | 2 +- examples/amp/build.zig | 32 ++++++++++++++++++++++++++++ examples/amp/{ => src}/amp.ttl | 0 examples/amp/{ => src}/amp.zig | 0 examples/fifths/build.zig | 32 ++++++++++++++++++++++++++++ examples/fifths/{ => src}/fifths.ttl | 0 examples/fifths/{ => src}/fifths.zig | 0 examples/params/build.zig | 32 ++++++++++++++++++++++++++++ examples/params/{ => src}/params.ttl | 0 examples/params/{ => src}/params.zig | 0 12 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 examples/amp/build.zig rename examples/amp/{ => src}/amp.ttl (100%) rename examples/amp/{ => src}/amp.zig (100%) create mode 100644 examples/fifths/build.zig rename examples/fifths/{ => src}/fifths.ttl (100%) rename examples/fifths/{ => src}/fifths.zig (100%) create mode 100644 examples/params/build.zig rename examples/params/{ => src}/params.ttl (100%) rename examples/params/{ => src}/params.zig (100%) diff --git a/README.md b/README.md index 1090c1e..28cae01 100644 --- a/README.md +++ b/README.md @@ -14,3 +14,21 @@ git clone --recurse-submodules https://github.com/ziglibs/zig-lv2 ## Getting Started Check out the example in `examples` which contains both sample Zig code as well as its corresponding Turtle manifest. + +Build the example plugins with: + +```bash +zig build examples +``` + +Then add `zig-out/` LV2 plugins path in your host. + +There are also example `build.zig` files you can use to build your plugin out of this tree: + +```bash +cp -r zig-lv2/examples/amp zig-amp +cd zig-amp/ +zig fetch --save ../zig-lv2/ +zig build +``` + diff --git a/build.zig b/build.zig index b4fa813..92675fb 100644 --- a/build.zig +++ b/build.zig @@ -45,14 +45,14 @@ pub fn build(b: *std.Build) !void { const examples_step = b.step("examples", "Build examples"); inline for (examples) |example| { - const source = b.path("examples/" ++ example ++ "/" ++ example ++ ".ttl"); + const source = b.path("examples/" ++ example ++ "/src/" ++ example ++ ".ttl"); const dest = example ++ ".lv2/manifest.ttl"; examples_step.dependOn(&b.addInstallFileWithDir(source, .prefix, dest).step); const dll = b.addSharedLibrary(.{ .name = example, - .root_source_file = b.path("examples/" ++ example ++ "/" ++ example ++ ".zig"), + .root_source_file = b.path("examples/" ++ example ++ "/src/" ++ example ++ ".zig"), .target = target, .optimize = optimize, .version = .{ .major = 0, .minor = 0, .patch = 2 }, diff --git a/build.zig.zon b/build.zig.zon index 234327c..229c5f6 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -6,7 +6,7 @@ // // It is redundant to include "zig" in this name because it is already // within the Zig package namespace. - .name = "lv2", + .name = .lv2, // This is a [Semantic Version](https://semver.org/). // In a future version of Zig it will be used for package deduplication. diff --git a/examples/amp/build.zig b/examples/amp/build.zig new file mode 100644 index 0000000..148c69c --- /dev/null +++ b/examples/amp/build.zig @@ -0,0 +1,32 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // get zig-lv2 dependency + const package = b.dependency("lv2", .{ + .target = target, + .optimize = optimize, + }); + const module = package.module("lv2"); + + // copy ttl + const source = "src/amp.ttl"; + const dest = "amp.lv2/manifest.ttl"; + b.installFile(source, dest); + + // build plugin + const dll = b.addSharedLibrary(.{ + .name = "amp", + .root_source_file = b.path("src/amp.zig"), + .target = target, + .optimize = optimize, + .version = .{ .major = 0, .minor = 0, .patch = 2 }, + }); + dll.root_module.addImport("lv2", module); + + b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ + .dest_dir = .{ .override = .{ .custom = "amp.lv2", } } + }).step); +} diff --git a/examples/amp/amp.ttl b/examples/amp/src/amp.ttl similarity index 100% rename from examples/amp/amp.ttl rename to examples/amp/src/amp.ttl diff --git a/examples/amp/amp.zig b/examples/amp/src/amp.zig similarity index 100% rename from examples/amp/amp.zig rename to examples/amp/src/amp.zig diff --git a/examples/fifths/build.zig b/examples/fifths/build.zig new file mode 100644 index 0000000..c2bba4e --- /dev/null +++ b/examples/fifths/build.zig @@ -0,0 +1,32 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // get zig-lv2 dependency + const package = b.dependency("lv2", .{ + .target = target, + .optimize = optimize, + }); + const module = package.module("lv2"); + + // copy ttl + const source = "src/fifths.ttl"; + const dest = "fifths.lv2/manifest.ttl"; + b.installFile(source, dest); + + // build plugin + const dll = b.addSharedLibrary(.{ + .name = "fifths", + .root_source_file = b.path("src/fifths.zig"), + .target = target, + .optimize = optimize, + .version = .{ .major = 0, .minor = 0, .patch = 2 }, + }); + dll.root_module.addImport("lv2", module); + + b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ + .dest_dir = .{ .override = .{ .custom = "fifths.lv2", } } + }).step); +} diff --git a/examples/fifths/fifths.ttl b/examples/fifths/src/fifths.ttl similarity index 100% rename from examples/fifths/fifths.ttl rename to examples/fifths/src/fifths.ttl diff --git a/examples/fifths/fifths.zig b/examples/fifths/src/fifths.zig similarity index 100% rename from examples/fifths/fifths.zig rename to examples/fifths/src/fifths.zig diff --git a/examples/params/build.zig b/examples/params/build.zig new file mode 100644 index 0000000..121dba7 --- /dev/null +++ b/examples/params/build.zig @@ -0,0 +1,32 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + // get zig-lv2 dependency + const package = b.dependency("lv2", .{ + .target = target, + .optimize = optimize, + }); + const module = package.module("lv2"); + + // copy ttl + const source = "src/params.ttl"; + const dest = "params.lv2/manifest.ttl"; + b.installFile(source, dest); + + // build plugin + const dll = b.addSharedLibrary(.{ + .name = "params", + .root_source_file = b.path("src/params.zig"), + .target = target, + .optimize = optimize, + .version = .{ .major = 0, .minor = 0, .patch = 2 }, + }); + dll.root_module.addImport("lv2", module); + + b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ + .dest_dir = .{ .override = .{ .custom = "params.lv2", } } + }).step); +} diff --git a/examples/params/params.ttl b/examples/params/src/params.ttl similarity index 100% rename from examples/params/params.ttl rename to examples/params/src/params.ttl diff --git a/examples/params/params.zig b/examples/params/src/params.zig similarity index 100% rename from examples/params/params.zig rename to examples/params/src/params.zig From 56e8ba709cdbfed466218b6d4feaae0a957de987 Mon Sep 17 00:00:00 2001 From: esteban Date: Sun, 10 Aug 2025 01:04:29 +0200 Subject: [PATCH 8/9] README.md typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28cae01..8662366 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Build the example plugins with: zig build examples ``` -Then add `zig-out/` LV2 plugins path in your host. +Then add `zig-out/` to the LV2 plugins path in your host. There are also example `build.zig` files you can use to build your plugin out of this tree: From 6ef36f3bb5d3b48f34ac7cb11a1065e695aeb68c Mon Sep 17 00:00:00 2001 From: esteban Date: Tue, 26 Aug 2025 22:21:56 +0200 Subject: [PATCH 9/9] bump zig version to 0.15.1 --- README.md | 4 +- build.zig | 80 +++++++++++++++++++--------------- build.zig.zon | 2 +- examples/amp/build.zig | 60 ++++++++++++++++--------- examples/fifths/build.zig | 32 -------------- examples/fifths/src/fifths.zig | 12 ++--- examples/params/build.zig | 32 -------------- examples/params/src/params.zig | 48 ++++++++++---------- src/atom/atom.zig | 5 ++- src/atom/forge.zig | 6 +-- src/c.zig | 4 +- src/lv2.zig | 34 ++++++--------- src/state.zig | 12 ++--- src/urid.zig | 6 +-- src/utils.zig | 2 +- 15 files changed, 149 insertions(+), 190 deletions(-) delete mode 100644 examples/fifths/build.zig delete mode 100644 examples/params/build.zig diff --git a/README.md b/README.md index 8662366..1b5dd6d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ A toolkit for LV2 plugin authors written in Zig. **WARNING: Here be dragons; tons of LV2 features aren't implemented and this isn't ready for production at all.** ## Zig version -Zig 0.14.0 +Zig 0.15.1 ## Installing ```bash @@ -23,7 +23,7 @@ zig build examples Then add `zig-out/` to the LV2 plugins path in your host. -There are also example `build.zig` files you can use to build your plugin out of this tree: +There are also an example `build.zig` file you can use to build your plugin out of this tree: ```bash cp -r zig-lv2/examples/amp zig-amp diff --git a/build.zig b/build.zig index 92675fb..12736d3 100644 --- a/build.zig +++ b/build.zig @@ -1,17 +1,10 @@ const std = @import("std"); -const examples = &[_][]const u8{"amp", "fifths", "params"}; - pub fn build(b: *std.Build) !void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); // Module - //const mod = b.createModule(.{ - //.root_source_file = b.path("src/lv2.zig"), - //.target = target, - //.optimize = optimize, - //}); const mod = b.addModule("lv2", .{ .root_source_file = b.path("src/lv2.zig"), .target = target, @@ -22,15 +15,16 @@ pub fn build(b: *std.Build) !void { .file = b.path("ext_lv2/atom_util.c") }); - // Library - const lib = b.addStaticLibrary(.{ + // Library + const lib = b.addLibrary(.{ .name = "lv2", + .linkage = .static, .root_module = mod, }); - lib.linkLibC(); - lib.addIncludePath(b.path("lv2")); - lib.addIncludePath(b.path("ext_lv2")); - b.installArtifact(lib); + lib.linkLibC(); + lib.addIncludePath(b.path("lv2")); + lib.addIncludePath(b.path("ext_lv2")); + b.installArtifact(lib); // // Unit tests for library // const lib_unit_tests = b.addTest(.{ @@ -41,31 +35,49 @@ pub fn build(b: *std.Build) !void { // const test_step = b.step("test", "Run unit tests"); // test_step.dependOn(&run_lib_unit_tests.step); - // Example generate step const examples_step = b.step("examples", "Build examples"); + const options = .{ + .optimize = optimize, + .target = target, + .lv2 = mod, + }; + + const examples = &[_][]const u8{"amp", "fifths", "params"}; + inline for (examples) |example| { - const source = b.path("examples/" ++ example ++ "/src/" ++ example ++ ".ttl"); - const dest = example ++ ".lv2/manifest.ttl"; + const stp = buildExample(b, options, example); + examples_step.dependOn(&stp.step); + } +} - examples_step.dependOn(&b.addInstallFileWithDir(source, .prefix, dest).step); +pub fn buildExample(b: *std.Build, options: anytype, comptime eg_name: []const u8) *std.Build.Step.InstallArtifact { + const cwd_path = "examples/" ++ eg_name ++ "/"; - const dll = b.addSharedLibrary(.{ - .name = example, - .root_source_file = b.path("examples/" ++ example ++ "/src/" ++ example ++ ".zig"), - .target = target, - .optimize = optimize, - .version = .{ .major = 0, .minor = 0, .patch = 2 }, - }); - dll.root_module.addImport("lv2", mod); + // build plugin + const dll = b.addLibrary(.{ + .name = eg_name, + .linkage = .dynamic, + .version = .{ .major = 0, .minor = 0, .patch = 2 }, + .root_module = b.createModule(.{ + .root_source_file = b.path(cwd_path ++ "src/" ++ eg_name ++ ".zig"), + .target = options.target, + .optimize = options.optimize, + }), + }); - const install_example_lib = b.addInstallArtifact(dll, .{ - .dest_dir = .{ - .override = .{ - .custom = example ++ ".lv2", - } - } - }); - examples_step.dependOn(&install_example_lib.step); - } + dll.root_module.addImport("lv2", options.lv2); + + // install plugin + const install_dll = b.addInstallArtifact(dll, .{ + .dest_dir = .{ .override = .{ .custom = eg_name ++ ".lv2", } } + }); + + // install manifest + const source = cwd_path ++ "src/" ++ eg_name ++ ".ttl"; + const dest = eg_name ++ ".lv2/manifest.ttl"; + const install_manifest = b.addInstallFileWithDir(b.path(source), .prefix, dest); + install_dll.step.dependOn(&install_manifest.step); + + return install_dll; } diff --git a/build.zig.zon b/build.zig.zon index 229c5f6..8f89777 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -28,7 +28,7 @@ // Tracks the earliest Zig version that the package considers to be a // supported use case. - .minimum_zig_version = "0.14.1", + .minimum_zig_version = "0.15.1", // This field is optional. // Each dependency must either provide a `url` and `hash`, or a `path`. diff --git a/examples/amp/build.zig b/examples/amp/build.zig index 148c69c..b5d4134 100644 --- a/examples/amp/build.zig +++ b/examples/amp/build.zig @@ -1,32 +1,50 @@ +// This builds the amp example plugin on its own +// +// To get the lv2 library dependency, first do : +// +// zig fetch --save ../../ + const std = @import("std"); +const eg_name = "amp"; +const cwd_path = ""; + pub fn build(b: *std.Build) !void { - const target = b.standardTargetOptions(.{}); - const optimize = b.standardOptimizeOption(.{}); + const options = .{ + .target = b.standardTargetOptions(.{}), + .optimize = b.standardOptimizeOption(.{}), + }; - // get zig-lv2 dependency - const package = b.dependency("lv2", .{ - .target = target, - .optimize = optimize, + // lv2 library + const lv2 = b.dependency("lv2", .{ + .target = options.target, + .optimize = options.optimize, }); - const module = package.module("lv2"); - - // copy ttl - const source = "src/amp.ttl"; - const dest = "amp.lv2/manifest.ttl"; - b.installFile(source, dest); // build plugin - const dll = b.addSharedLibrary(.{ - .name = "amp", - .root_source_file = b.path("src/amp.zig"), - .target = target, - .optimize = optimize, + const dll = b.addLibrary(.{ + .name = eg_name, + .linkage = .dynamic, .version = .{ .major = 0, .minor = 0, .patch = 2 }, + .root_module = b.createModule(.{ + .root_source_file = b.path(cwd_path ++ "src/" ++ eg_name ++ ".zig"), + .target = options.target, + .optimize = options.optimize, + }), }); - dll.root_module.addImport("lv2", module); - b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ - .dest_dir = .{ .override = .{ .custom = "amp.lv2", } } - }).step); + dll.root_module.addImport("lv2", lv2.module("lv2")); + + // install plugin + const install_dll = b.addInstallArtifact(dll, .{ + .dest_dir = .{ .override = .{ .custom = eg_name ++ ".lv2", } } + }); + + // install manifest + const source = cwd_path ++ "src/" ++ eg_name ++ ".ttl"; + const dest = eg_name ++ ".lv2/manifest.ttl"; + const install_manifest = b.addInstallFileWithDir(b.path(source), .prefix, dest); + install_dll.step.dependOn(&install_manifest.step); + + b.getInstallStep().dependOn(&install_dll.step); } diff --git a/examples/fifths/build.zig b/examples/fifths/build.zig deleted file mode 100644 index c2bba4e..0000000 --- a/examples/fifths/build.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); - -pub fn build(b: *std.Build) !void { - const target = b.standardTargetOptions(.{}); - const optimize = b.standardOptimizeOption(.{}); - - // get zig-lv2 dependency - const package = b.dependency("lv2", .{ - .target = target, - .optimize = optimize, - }); - const module = package.module("lv2"); - - // copy ttl - const source = "src/fifths.ttl"; - const dest = "fifths.lv2/manifest.ttl"; - b.installFile(source, dest); - - // build plugin - const dll = b.addSharedLibrary(.{ - .name = "fifths", - .root_source_file = b.path("src/fifths.zig"), - .target = target, - .optimize = optimize, - .version = .{ .major = 0, .minor = 0, .patch = 2 }, - }); - dll.root_module.addImport("lv2", module); - - b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ - .dest_dir = .{ .override = .{ .custom = "fifths.lv2", } } - }).step); -} diff --git a/examples/fifths/src/fifths.zig b/examples/fifths/src/fifths.zig index 3923a75..ac645b5 100644 --- a/examples/fifths/src/fifths.zig +++ b/examples/fifths/src/fifths.zig @@ -12,7 +12,7 @@ pub const FifthsURIs = struct { patch_property: u32, patch_value: u32, - pub fn map(self: *@This(), map_: *lv2.URIDMap) void { + pub fn map(self: *@This(), map_: *lv2.urid.URIDMap) void { self.atom_path = map_.map(lv2.c.LV2_ATOM__Path); self.atom_resource = map_.map(lv2.c.LV2_ATOM__Resource); self.atom_sequence = map_.map(lv2.c.LV2_ATOM__Sequence); @@ -28,10 +28,10 @@ pub const FifthsURIs = struct { pub const Fifths = lv2.Plugin{ .uri = "http://augustera.me/fifths", .Handle = struct { - in: *lv2.AtomSequence, - out: *lv2.AtomSequence, + in: *lv2.atom.AtomSequence, + out: *lv2.atom.AtomSequence, - map: *lv2.URIDMap, + map: *lv2.urid.URIDMap, uris: FifthsURIs }, }; @@ -53,7 +53,7 @@ fn instantiate ( _ = bundle_path; _ = descriptor; _ = rate; - handle.map = features.query(lv2.URIDMap).?; + handle.map = features.query(lv2.urid.URIDMap).?; handle.uris.map(handle.map); } @@ -65,7 +65,7 @@ const MidiNoteData = extern struct { }; const MidiNoteEvent = extern struct { - event: lv2.AtomEvent, + event: lv2.atom.AtomEvent, data: MidiNoteData }; diff --git a/examples/params/build.zig b/examples/params/build.zig deleted file mode 100644 index 121dba7..0000000 --- a/examples/params/build.zig +++ /dev/null @@ -1,32 +0,0 @@ -const std = @import("std"); - -pub fn build(b: *std.Build) !void { - const target = b.standardTargetOptions(.{}); - const optimize = b.standardOptimizeOption(.{}); - - // get zig-lv2 dependency - const package = b.dependency("lv2", .{ - .target = target, - .optimize = optimize, - }); - const module = package.module("lv2"); - - // copy ttl - const source = "src/params.ttl"; - const dest = "params.lv2/manifest.ttl"; - b.installFile(source, dest); - - // build plugin - const dll = b.addSharedLibrary(.{ - .name = "params", - .root_source_file = b.path("src/params.zig"), - .target = target, - .optimize = optimize, - .version = .{ .major = 0, .minor = 0, .patch = 2 }, - }); - dll.root_module.addImport("lv2", module); - - b.getInstallStep().dependOn(&b.addInstallArtifact(dll, .{ - .dest_dir = .{ .override = .{ .custom = "params.lv2", } } - }).step); -} diff --git a/examples/params/src/params.zig b/examples/params/src/params.zig index c6c75dc..1586518 100644 --- a/examples/params/src/params.zig +++ b/examples/params/src/params.zig @@ -14,7 +14,7 @@ pub const URIs = struct { patch_property: u32, patch_value: u32, - pub fn map(self: *@This(), map_: *lv2.URIDMap) void { + pub fn map(self: *@This(), map_: *lv2.urid.URIDMap) void { self.atom_path = map_.map(lv2.c.LV2_ATOM__Path); self.atom_resource = map_.map(lv2.c.LV2_ATOM__Resource); self.atom_sequence = map_.map(lv2.c.LV2_ATOM__Sequence); @@ -29,17 +29,17 @@ pub const URIs = struct { } }; -pub const StateManager = lv2.StateManager( +pub const StateManager = lv2.state.StateManager( struct { - aint: lv2.AtomInt, - along: lv2.AtomLong, - afloat: lv2.AtomFloat, - adouble: lv2.AtomDouble, - abool: lv2.AtomBool, - astring: lv2.AtomString(1024), - apath: lv2.AtomPath(1024), - lfo: lv2.AtomFloat, - spring: lv2.AtomFloat + aint: lv2.atom.AtomInt, + along: lv2.atom.AtomLong, + afloat: lv2.atom.AtomFloat, + adouble: lv2.atom.AtomDouble, + abool: lv2.atom.AtomBool, + astring: lv2.atom.AtomString(1024), + apath: lv2.atom.AtomPath(1024), + lfo: lv2.atom.AtomFloat, + spring: lv2.atom.AtomFloat }, Params.Handle ); @@ -48,13 +48,13 @@ pub const Params = lv2.Plugin{ .uri = "http://augustera.me/params", .Handle = struct { // Ports - in: *lv2.AtomSequence, - out: *lv2.AtomSequence, + in: *lv2.atom.AtomSequence, + out: *lv2.atom.AtomSequence, // Features - map: *lv2.URIDMap, - unmap: *lv2.URIDUnmap, - forge: lv2.AtomForge, + map: *lv2.urid.URIDMap, + unmap: *lv2.urid.URIDUnmap, + forge: lv2.atom.forge.AtomForge, // URIs uris: URIs, @@ -87,8 +87,8 @@ fn instantiate ( _ = rate; _ = bundle_path; - handle.map = features.query(lv2.URIDMap).?; - handle.unmap = features.query(lv2.URIDUnmap).?; + handle.map = features.query(lv2.urid.URIDMap).?; + handle.unmap = features.query(lv2.urid.URIDUnmap).?; handle.forge.init(handle.map); handle.uris.map(handle.map); @@ -121,11 +121,11 @@ fn run(handle: *Params.Handle, samples: u32) void { while (iter.next()) |event| { var obj = event.toAtomObject(); if (obj.body.kind == handle.uris.patch_set) { - var subject: ?*lv2.AtomURID = null; - var property: ?*lv2.AtomURID = null; - var value: ?*lv2.Atom = null; + var subject: ?*lv2.atom.AtomURID = null; + var property: ?*lv2.atom.AtomURID = null; + var value: ?*lv2.atom.Atom = null; - obj.query(&[_]lv2.AtomObjectQuery{ + obj.query(&[_]lv2.atom.AtomObjectQuery{ .{ .key = handle.uris.patch_subject, .value = @ptrCast(&subject) }, .{ .key = handle.uris.patch_property, .value = @ptrCast(&property) }, .{ .key = handle.uris.patch_value, .value = &value } @@ -140,7 +140,7 @@ fn run(handle: *Params.Handle, samples: u32) void { const out_size = handle.out.atom.size; handle.forge.setBuffer(handle.out.toBuffer(), out_size); - var out_frame : lv2.AtomForgeFrame = std.mem.zeroes(lv2.AtomForgeFrame); + var out_frame : lv2.atom.forge.AtomForgeFrame = std.mem.zeroes(lv2.atom.forge.AtomForgeFrame); _ = handle.forge.writeSequenceHead(&out_frame, 0); if ( handle.state_manager.state.spring.body > 0.0 ) { @@ -154,7 +154,7 @@ fn run(handle: *Params.Handle, samples: u32) void { // spring value patch set event _ = handle.forge.writeFrameTime(0); - var spring_frame : lv2.AtomForgeFrame = std.mem.zeroes(lv2.AtomForgeFrame); + var spring_frame : lv2.atom.forge.AtomForgeFrame = std.mem.zeroes(lv2.atom.forge.AtomForgeFrame); _ = handle.forge.writeObject(&spring_frame, 0, handle.uris.patch_set); _ = handle.forge.writeKey(handle.uris.patch_property); _ = handle.forge.writeAtomURID(handle.state_manager.state_urid_map.spring); diff --git a/src/atom/atom.zig b/src/atom/atom.zig index bc75bdd..1f0ce77 100644 --- a/src/atom/atom.zig +++ b/src/atom/atom.zig @@ -1,10 +1,11 @@ -const c = @import("../c.zig"); +const c = @import("../c.zig").headers; const std = @import("std"); const urid = @import("../urid.zig"); +pub const forge = @import("forge.zig"); pub const Atom = extern struct { const Self = @This(); - + size: urid.URID, kind: urid.URID }; diff --git a/src/atom/forge.zig b/src/atom/forge.zig index fc272ee..eecabdd 100644 --- a/src/atom/forge.zig +++ b/src/atom/forge.zig @@ -1,12 +1,12 @@ -const c = @import("../c.zig"); +const c = @import("../c.zig").headers; const std = @import("std"); const atom = @import("atom.zig"); const urid = @import("../urid.zig"); pub const AtomForgeSinkHandle = ?*anyopaque; pub const AtomForgeRef = isize; -pub const AtomForgeSink = ?*fn (sink_handle: AtomForgeSinkHandle, buf: ?*const anyopaque, size: u32) callconv(.C) AtomForgeRef; -pub const AtomForgeDerefFunc = ?*fn (sink_handle: AtomForgeSinkHandle, ref: AtomForgeRef) callconv(.C) [*c]atom.Atom; +pub const AtomForgeSink = ?*fn (sink_handle: AtomForgeSinkHandle, buf: ?*const anyopaque, size: u32) callconv(.c) AtomForgeRef; +pub const AtomForgeDerefFunc = ?*fn (sink_handle: AtomForgeSinkHandle, ref: AtomForgeRef) callconv(.c) [*c]atom.Atom; pub const AtomForgeFrame = extern struct { parent: ?*AtomForgeFrame, diff --git a/src/c.zig b/src/c.zig index a91f5aa..8414e72 100644 --- a/src/c.zig +++ b/src/c.zig @@ -1,4 +1,4 @@ -pub usingnamespace @cImport({ +pub const headers = @cImport({ @cInclude("lv2/core/lv2.h"); @cInclude("lv2/core/lv2_util.h"); @cInclude("lv2/log/log.h"); @@ -6,7 +6,7 @@ pub usingnamespace @cImport({ @cInclude("lv2/urid/urid.h"); @cInclude("lv2/atom/atom.h"); - //@cInclude("lv2/atom/util.h"); + @cInclude("atom_util.h"); @cInclude("lv2/atom/forge.h"); diff --git a/src/lv2.zig b/src/lv2.zig index 53b5978..fd1ecb9 100644 --- a/src/lv2.zig +++ b/src/lv2.zig @@ -1,17 +1,11 @@ const std = @import("std"); -pub const c = @import("c.zig"); - -pub usingnamespace @import("urid.zig"); - -pub usingnamespace @import("atom/atom.zig"); -pub usingnamespace @import("atom/forge.zig"); - -pub usingnamespace @import("state.zig"); -pub usingnamespace @import("utils.zig"); +pub const c = @import("c.zig").headers; +pub const urid = @import("urid.zig"); +pub const atom = @import("atom/atom.zig"); +pub const state = @import("state.zig"); pub const utils = @import("utils.zig"); - -//const ra = @import("random_access.zig"); +pub const Features = utils.Features; pub const Descriptor = c.LV2_Descriptor; @@ -39,12 +33,11 @@ pub const Plugin = struct { return @ptrCast(@alignCast(instance)); } - pub fn instantiate(descriptor: [*c]const Descriptor, rate: f64, bundle_path: [*c]const u8, features: [*c]const [*c]const c.LV2_Feature) callconv(.C) c.LV2_Handle { + pub fn instantiate(descriptor: [*c]const Descriptor, rate: f64, bundle_path: [*c]const u8, features: [*c]const [*c]const c.LV2_Feature) callconv(.c) c.LV2_Handle { const handle = std.heap.c_allocator.create(Handle__) catch { std.debug.print("Yeah you're kinda screwed!", .{}); @trap(); - //std.os.exit(1); }; if (handlers.instantiate) |act| { @@ -53,17 +46,16 @@ pub const Plugin = struct { std.heap.c_allocator.destroy(handle); @trap(); }; - //std.os.exit(1); } return @ptrCast(handle); } - pub fn cleanup(instance: c.LV2_Handle) callconv(.C) void { + pub fn cleanup(instance: c.LV2_Handle) callconv(.c) void { std.heap.c_allocator.destroy(toHandle(instance)); } - pub fn connect_port(instance: c.LV2_Handle, port: u32, data: ?*anyopaque) callconv(.C) void { + pub fn connect_port(instance: c.LV2_Handle, port: u32, data: ?*anyopaque) callconv(.c) void { var hnd = toHandle(instance); inline for (std.meta.fields(@TypeOf(hnd.*)), 0..) |field, i| { @@ -77,26 +69,26 @@ pub const Plugin = struct { } } - pub fn activate(instance: c.LV2_Handle) callconv(.C) void { + pub fn activate(instance: c.LV2_Handle) callconv(.c) void { if (handlers.activate) |act| act(toHandle(instance)); } - pub fn deactivate(instance: c.LV2_Handle) callconv(.C) void { + pub fn deactivate(instance: c.LV2_Handle) callconv(.c) void { if (handlers.deactivate) |deact| deact(toHandle(instance)); } - pub fn extension_data(uri: [*c]const u8) callconv(.C) ?*anyopaque { + pub fn extension_data(uri: [*c]const u8) callconv(.c) ?*anyopaque { if (handlers.extensionData) |rn| return rn(std.mem.span(uri)); return null; } - pub fn run(instance: c.LV2_Handle, n_samples: u32) callconv(.C) void { + pub fn run(instance: c.LV2_Handle, n_samples: u32) callconv(.c) void { if (handlers.run) |rn| rn(toHandle(instance), n_samples); } pub const __globalDescriptor = Descriptor{ .URI = URI_.ptr, .instantiate = instantiate, .connect_port = connect_port, .activate = activate, .run = run, .deactivate = deactivate, .cleanup = cleanup, .extension_data = extension_data }; - pub fn lv2_descriptor(index: u32) callconv(.C) [*c]const Descriptor { + pub fn lv2_descriptor(index: u32) callconv(.c) [*c]const Descriptor { return if (index == 0) &__globalDescriptor else null; } }; diff --git a/src/state.zig b/src/state.zig index 1927d6f..2d9789d 100644 --- a/src/state.zig +++ b/src/state.zig @@ -44,7 +44,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { state_urid_map: StateMap(State), state_type_map: StateMap(State), - pub fn map(self: *Self, comptime uri: []const u8, map_: *lv2.URIDMap) void { + pub fn map(self: *Self, comptime uri: []const u8, map_: *lv2.urid.URIDMap) void { inline for (std.meta.fields(State)) |field| { @field(self.state_urid_map, field.name) = map_.map(uri ++ "#" ++ field.name); @@ -70,7 +70,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { } else return null; } - pub fn setParameter(self: *Self, field_urid: lv2.URID, value: *lv2.Atom) void { + pub fn setParameter(self: *Self, field_urid: lv2.urid.URID, value: *lv2.atom.Atom) void { inline for (std.meta.fields(StateMap(State))) |s| { if (@field(self.state_urid_map, s.name) == field_urid) { const to = *@TypeOf(@field(self.state, s.name)); @@ -85,7 +85,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { // This is used in the usual way when called by the host to save plugin state, // but also internally for writing messages in the audio thread by passing a // "store" function which actually writes the description to the forge. - pub fn save (handle: lv2.c.LV2_Handle, store: lv2.c.LV2_State_Store_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { + pub fn save (handle: lv2.c.LV2_Handle, store: lv2.c.LV2_State_Store_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.c) lv2.c.LV2_State_Status { if (store == null) return 0; const plug_ptr : *PluginHandle = @ptrCast(@alignCast(handle)); @@ -105,7 +105,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { status = store.?( state_handle, key, - @ptrFromInt(@intFromPtr(&value) + @sizeOf(lv2.Atom)), + @ptrFromInt(@intFromPtr(&value) + @sizeOf(lv2.atom.Atom)), value.atom.size, kind, lv2.c.LV2_STATE_IS_POD | lv2.c.LV2_STATE_IS_PORTABLE @@ -115,7 +115,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { return status; } - pub fn restore (handle: lv2.c.LV2_Handle, retrieve: lv2.c.LV2_State_Retrieve_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.C) lv2.c.LV2_State_Status { + pub fn restore (handle: lv2.c.LV2_Handle, retrieve: lv2.c.LV2_State_Retrieve_Function, state_handle: lv2.c.LV2_State_Handle, flags: u32, features: [*c]const [*c]const lv2.c.LV2_Feature) callconv(.c) lv2.c.LV2_State_Status { const plug_ptr : *PluginHandle = @ptrCast(@alignCast(handle)); const state_parent_ptr : *Self = &(plug_ptr.*.state_manager); @@ -138,7 +138,7 @@ pub fn StateManager(comptime State: type, comptime PluginHandle: type) type { const to = @TypeOf(@field(state_parent_ptr.state, field.name).body); const atm : *const to = @ptrCast(@alignCast(v)); @field(state_parent_ptr.state, field.name).body = atm.*; - @field(state_parent_ptr.state, field.name).atom.size = std.math.cast(lv2.URID, vsize) orelse 0; + @field(state_parent_ptr.state, field.name).atom.size = std.math.cast(lv2.urid.URID, vsize) orelse 0; @field(state_parent_ptr.state, field.name).atom.kind = vtype; } else status = 4; diff --git a/src/urid.zig b/src/urid.zig index bada117..94033b0 100644 --- a/src/urid.zig +++ b/src/urid.zig @@ -1,4 +1,4 @@ -const c = @import("c.zig"); +const c = @import("c.zig").headers; pub const URID = u32; @@ -9,7 +9,7 @@ pub const URIDMap = extern struct { const Self = @This(); handle: MapHandle, - map_: ?*const fn (MapHandle, [*c]const u8) callconv(.C) URID, + map_: ?*const fn (MapHandle, [*c]const u8) callconv(.c) URID, pub fn fromData(data: *anyopaque) *Self { return @ptrCast(@alignCast(data)); @@ -28,7 +28,7 @@ pub const URIDUnmap = extern struct { const Self = @This(); handle: UnmapHandle, - unmap_: ?*fn (UnmapHandle, URID) callconv(.C) [*c]const u8, + unmap_: ?*fn (UnmapHandle, URID) callconv(.c) [*c]const u8, pub fn fromData(data: *anyopaque) *Self { return @ptrCast(@alignCast(data)); diff --git a/src/utils.zig b/src/utils.zig index e67ff32..599435e 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -1,4 +1,4 @@ -const c = @import("c.zig"); +const c = @import("c.zig").headers; const std = @import("std"); pub const Logger = struct {