Skip to content

Commit 4dcee52

Browse files
authored
move NeuralAudio implementation to pdnam+; create new MicroNam called pdnam~ (#3)
* move NeuralAudio implementation to pdnam+; create new MicroNam called pdnam~ * add various models for pdnam~
1 parent 9882a4b commit 4dcee52

12 files changed

Lines changed: 308 additions & 93 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
# ===============================================================
1212
# ===============================================================
1313
Linux-amd64:
14-
runs-on: ubuntu-latest
14+
runs-on: ubuntu-22.04
1515
steps:
1616
- uses: actions/checkout@v6
1717
with:
@@ -41,7 +41,7 @@ jobs:
4141
# ===============================================================
4242
# ===============================================================
4343
Linux-arm64:
44-
runs-on: ubuntu-24.04-arm
44+
runs-on: ubuntu-22.04-arm
4545
steps:
4646
- uses: actions/checkout@v6
4747
with:

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,9 @@
44
[submodule "dep/pd-lib-builder"]
55
path = dep/pd-lib-builder
66
url = https://github.com/pure-data/pd-lib-builder.git
7+
[submodule "dep/json"]
8+
path = dep/json
9+
url = https://github.com/nlohmann/json.git
10+
[submodule "dep/MicroNAM"]
11+
path = dep/MicroNAM
12+
url = https://github.com/jaffco/MicroNAM.git

Makefile

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
lib.name = pdnam~
2-
3-
class.sources = pdnam~.cpp
1+
lib.name = PDNAM
42

53
datafiles = \
64
pdnam~-help.pd \
5+
pdnam+~-help.pd \
76
README.md \
87
LICENSE
98

109
datadirs = data/
1110

12-
common.sources = \
11+
# pdnam~ only needs its own source (header-only MicroNAM + nlohmann/json)
12+
pdnam~.class.sources = pdnam~.cpp
13+
14+
# pdnam+~ needs NeuralAudio implementation
15+
pdnam+~.class.sources = pdnam+~.cpp \
1316
dep/NeuralAudio/NeuralAudio/NeuralModel.cpp \
1417
dep/NeuralAudio/NeuralAudio/RTNeuralLoader.cpp \
1518
dep/NeuralAudio/deps/RTNeural/RTNeural/RTNeural.cpp \
@@ -32,7 +35,8 @@ cflags = -std=gnu++20 -DNAM_SAMPLE_FLOAT -DDSP_SAMPLE_FLOAT \
3235
-Idep/NeuralAudio/deps/RTNeural/modules/json \
3336
-Idep/NeuralAudio/deps/RTNeural-NAM \
3437
-Idep/NeuralAudio/deps/RTNeural-NAM/wavenet \
35-
-Idep/NeuralAudio/deps/RTNeural/modules/xsimd/include
38+
-Idep/NeuralAudio/deps/RTNeural/modules/xsimd/include \
39+
-Idep/MicroNAM -Idep/json/single_include
3640

3741
define forDarwin
3842
cflags += -mmacosx-version-min=10.15

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
# PDNAM
22

3-
Basic [NAM](https://www.neuralampmodeler.com/) loader external for Pure Data. The external is deliberatily minimal with no additional options. The only argument is a relative path to a model file to load.
3+
Basic [NAM](https://www.neuralampmodeler.com/) loader externals for Pure Data. These externals are deliberately minimal with no additional options. The only argument is a relative path to a model file to load.
44

5-
It uses the [NeuralAudio](https://github.com/mikeoliphant/NeuralAudio) implementation and supports the optimized WaveNet and LSTM architectures. And it can load `.nam`, `.json` and `.aidax` files.
5+
`pdnam~` uses the [MicroNAM](https://github.com/jaffco/MicroNAM) implementation and supports the four WaveNet model types: Nano, Feather, Lite, and Standard.
66

7-
Two example models are included from the NeuralAudio library.
7+
`pdnam+~` uses the [NeuralAudio](https://github.com/mikeoliphant/NeuralAudio) implementation and supports both the optimized WaveNet and LSTM architectures.
8+
9+
Several example models are included for testing.
810

911
## License
1012

11-
This project is released under the MIT license.
13+
This project is released under the MIT license. As are MicroNAM and NeuralAudio.
14+
15+
"BossWN" WaveNet models come from NeuralAudio and are under MIT.
1216

1317
The "tw40_blues_deluxe_deerinkstudios.json" and "Tomato_Preamp_Maximum_Gain.aidax" models are under the CC BY-NC-ND 4.0 license.

data/BossWN-feather.nam

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

data/BossWN-standard.nam

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

dep/MicroNAM

Submodule MicroNAM added at 83dd7de

dep/json

Submodule json added at 98386eb

pdnam+~-help.pd

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#N canvas 978 285 524 488 10;
2+
#X obj 52 297 dac~;
3+
#X obj 51 18 noise~;
4+
#X obj 51 87 *~;
5+
#X obj 118 39 line~;
6+
#X msg 118 16 1 \, 0 300;
7+
#X obj 119 86 *~;
8+
#X obj 186 38 line~;
9+
#X msg 186 15 1 \, 0 300;
10+
#X obj 182 85 *~;
11+
#X obj 249 37 line~;
12+
#X msg 249 14 1 \, 0 300;
13+
#X obj 52 154 pdnam+~ data/tw40_blues_deluxe_deerinkstudios.json;
14+
#X obj 120 184 pdnam+~ data/BossWN-nano.nam;
15+
#X obj 181 216 pdnam+~ data/Tomato_Preamp_Maximum_Gain.aidax;
16+
#X connect 1 0 2 0;
17+
#X connect 1 0 5 0;
18+
#X connect 1 0 8 0;
19+
#X connect 2 0 11 0;
20+
#X connect 3 0 2 1;
21+
#X connect 4 0 3 0;
22+
#X connect 5 0 12 0;
23+
#X connect 6 0 5 1;
24+
#X connect 7 0 6 0;
25+
#X connect 8 0 13 0;
26+
#X connect 9 0 8 1;
27+
#X connect 10 0 9 0;
28+
#X connect 11 0 0 0;
29+
#X connect 11 0 0 1;
30+
#X connect 12 0 0 0;
31+
#X connect 12 0 0 1;
32+
#X connect 13 0 0 0;
33+
#X connect 13 0 0 1;

pdnam+~.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// PDNAM
2+
// Copyright (C) 2026 Wasted Audio
3+
//
4+
// SPDX-License-Identifier: MIT
5+
6+
#include "m_pd.h"
7+
#include "g_canvas.h"
8+
#include "NeuralAudio/NeuralModel.h"
9+
#include <iostream>
10+
#include <string>
11+
#include <filesystem>
12+
13+
static t_class *pdnam_plus_tilde_class;
14+
15+
typedef struct _pdnam_plus_tilde {
16+
t_object x_obj;
17+
t_sample f;
18+
t_canvas* canvas;
19+
NeuralAudio::NeuralModel* model;
20+
} t_pdnam_plus_tilde;
21+
22+
static void pdnam_plus_tilde_load(t_pdnam_plus_tilde *x, t_symbol *model_path)
23+
{
24+
if (x->model) {
25+
delete x->model;
26+
x->model = nullptr;
27+
}
28+
29+
if (model_path == &s_) return;
30+
31+
// Resolve relative path
32+
char buf[MAXPDSTRING];
33+
canvas_makefilename(x->canvas, model_path->s_name, buf, MAXPDSTRING);
34+
std::filesystem::path path(buf);
35+
36+
if (!std::filesystem::exists(path) || !std::filesystem::is_regular_file(path)) {
37+
pd_error(x, "pdnam+~: model file not found: %s", buf);
38+
return;
39+
}
40+
41+
try {
42+
x->model = NeuralAudio::NeuralModel::CreateFromFile(path);
43+
if (x->model) {
44+
post("pdnam+~: loaded model %s", model_path->s_name);
45+
} else {
46+
pd_error(x, "pdnam+~: failed to load model %s", model_path->s_name);
47+
}
48+
} catch (const std::exception& e) {
49+
pd_error(x, "pdnam+~: exception loading model: %s", e.what());
50+
} catch (...) {
51+
pd_error(x, "pdnam+~: unknown exception loading model");
52+
}
53+
}
54+
55+
void *pdnam_plus_tilde_new(t_symbol *s, int argc, t_atom *argv)
56+
{
57+
t_pdnam_plus_tilde *x = (t_pdnam_plus_tilde *)pd_new(pdnam_plus_tilde_class);
58+
x->canvas = canvas_getcurrent();
59+
x->model = nullptr;
60+
61+
t_symbol* model_path = (argc >= 1 && argv[0].a_type == A_SYMBOL)
62+
? atom_getsymbol(&argv[0])
63+
: &s_;
64+
65+
pdnam_plus_tilde_load(x, model_path);
66+
67+
outlet_new(&x->x_obj, &s_signal);
68+
69+
return (void *)x;
70+
}
71+
72+
t_int *pdnam_plus_tilde_perform(t_int *w)
73+
{
74+
t_pdnam_plus_tilde *x = (t_pdnam_plus_tilde *)(w[1]);
75+
t_sample *in = (t_sample *)(w[2]);
76+
t_sample *out = (t_sample *)(w[3]);
77+
int n = (int)(w[4]);
78+
79+
if (x->model) {
80+
x->model->Process(in, out, n);
81+
} else {
82+
while (n--) {
83+
*out++ = *in++;
84+
}
85+
}
86+
87+
return (w+5);
88+
}
89+
90+
void pdnam_plus_tilde_dsp(t_pdnam_plus_tilde *x, t_signal **sp)
91+
{
92+
dsp_add(pdnam_plus_tilde_perform, 4, x,
93+
sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
94+
}
95+
96+
void pdnam_plus_tilde_free(t_pdnam_plus_tilde *x)
97+
{
98+
if (x->model) delete x->model;
99+
}
100+
101+
extern "C" void setup_pdnam0x2b_tilde(void) {
102+
pdnam_plus_tilde_class = class_new(gensym("pdnam+~"),
103+
(t_newmethod)pdnam_plus_tilde_new,
104+
(t_method)pdnam_plus_tilde_free, sizeof(t_pdnam_plus_tilde),
105+
CLASS_DEFAULT, A_GIMME, 0);
106+
107+
class_addmethod(pdnam_plus_tilde_class,
108+
(t_method)pdnam_plus_tilde_dsp, gensym("dsp"), A_CANT, 0);
109+
CLASS_MAINSIGNALIN(pdnam_plus_tilde_class, t_pdnam_plus_tilde, f);
110+
}

0 commit comments

Comments
 (0)