Skip to content

Commit f33ddcb

Browse files
committed
first setup of rfft~ components
1 parent e7c9639 commit f33ddcb

11 files changed

Lines changed: 2461 additions & 0 deletions

File tree

hvcc/core/hv2ir/HIrRFFT.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Copyright (C) 2014-2018 Enzien Audio, Ltd.
2+
# Copyright (C) 2023 Wasted Audio
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
from typing import Dict, Optional
18+
19+
from .HeavyIrObject import HeavyIrObject
20+
from .HeavyGraph import HeavyGraph
21+
22+
23+
class HIrRFFT(HeavyIrObject):
24+
""" __rfft~f
25+
"""
26+
27+
def __init__(
28+
self,
29+
obj_type: str,
30+
args: Optional[Dict] = None,
31+
graph: Optional[HeavyGraph] = None,
32+
annotations: Optional[Dict] = None
33+
) -> None:
34+
assert obj_type in {"__rfft~f", "__rifft~f"}
35+
super().__init__(obj_type, args=args, graph=graph, annotations=annotations)
36+
37+
def reduce(self) -> Optional[tuple]:
38+
if self.graph is not None:
39+
table_obj = self.graph.resolve_object_for_name(
40+
self.args["table"],
41+
["table", "__table"])
42+
if table_obj is not None:
43+
self.args["table_id"] = table_obj.id
44+
return ({self}, [])
45+
else:
46+
self.add_error(f"Cannot find table named \"{self.args['table']}\" for object {self}.")
47+
48+
return None

hvcc/core/json/heavy.ir.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,6 +2223,60 @@
22232223
"-->"
22242224
]
22252225
},
2226+
"__rfft~f": {
2227+
"inlets": [
2228+
"~f>",
2229+
"-->",
2230+
"-->"
2231+
],
2232+
"ir": {
2233+
"control": false,
2234+
"signal": true,
2235+
"init": true
2236+
},
2237+
"outlets": [
2238+
"~f>",
2239+
"~f>"
2240+
],
2241+
"args": [{
2242+
"name": "table_id",
2243+
"value_type": "string",
2244+
"description": "",
2245+
"default": "",
2246+
"required": true
2247+
}],
2248+
"perf": {
2249+
"avx": 0,
2250+
"sse": 0
2251+
}
2252+
},
2253+
"__rifft~f": {
2254+
"inlets": [
2255+
"~f>",
2256+
"~f>",
2257+
"-->",
2258+
"-->"
2259+
],
2260+
"ir": {
2261+
"control": false,
2262+
"signal": true,
2263+
"init": true
2264+
},
2265+
"outlets": [
2266+
"~f>"
2267+
],
2268+
"args": [{
2269+
"name": "table_id",
2270+
"value_type": "string",
2271+
"description": "",
2272+
"default": "",
2273+
"required": true
2274+
}],
2275+
"perf": {
2276+
"avx": 0,
2277+
"sse": 0
2278+
}
2279+
},
22262280
"__rpole~f": {
22272281
"inlets": [
22282282
"~f>",

hvcc/generators/ir2c/SignalRFFT.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Copyright (C) 2014-2018 Enzien Audio, Ltd.
2+
# Copyright (C) 2023 Wasted Audio
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
17+
from typing import Dict, List
18+
19+
from .HeavyObject import HeavyObject
20+
21+
22+
class SignalRFFT(HeavyObject):
23+
24+
c_struct = "SignalRFFT"
25+
preamble = "sRFFT"
26+
27+
@classmethod
28+
def get_C_header_set(cls) -> set:
29+
return {"HvSignalRFFT.h"}
30+
31+
@classmethod
32+
def get_C_file_set(cls) -> set:
33+
return {"HvSignalRFFT.h", "HvSignalRFFT.c", "pffft.h", "pffft.c"}
34+
35+
@classmethod
36+
def get_C_init(cls, obj_type: str, obj_id: int, args: Dict) -> List[str]:
37+
return [
38+
"sRFFT_init(&sRFFT_{0}, &hTable_{1}, {2});".format(
39+
obj_id,
40+
args["table_id"],
41+
64)
42+
]
43+
44+
@classmethod
45+
def get_C_onMessage(cls, obj_type: str, obj_id: int, inlet_index: int, args: Dict) -> List[str]:
46+
return [
47+
"sRFFT_onMessage(_c, &Context(_c)->sRFFT_{0}, {1}, m, NULL);".format(
48+
obj_id,
49+
inlet_index)
50+
]
51+
52+
@classmethod
53+
def get_C_process(cls, process_dict: Dict, obj_type: str, obj_id: int, args: Dict) -> List[str]:
54+
if obj_type == "__rfft~f":
55+
return [
56+
"__hv_rfft_f(&sRFFT_{0}, VIf({1}), VOf({2}), VOf({3}));".format(
57+
process_dict["id"],
58+
cls._c_buffer(process_dict["inputBuffers"][0]),
59+
cls._c_buffer(process_dict["outputBuffers"][0]),
60+
cls._c_buffer(process_dict["outputBuffers"][1])
61+
)
62+
]
63+
elif obj_type == "__rifft~f":
64+
return [
65+
"__hv_rifft_f(&sRFFT_{0}, VIf({1}), VIf({2}), VOf({3}));".format(
66+
process_dict["id"],
67+
cls._c_buffer(process_dict["inputBuffers"][0]),
68+
cls._c_buffer(process_dict["inputBuffers"][1]),
69+
cls._c_buffer(process_dict["outputBuffers"][0])
70+
)
71+
]
72+
else:
73+
raise Exception

hvcc/generators/ir2c/ir2c.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from hvcc.generators.ir2c.SignalLorenz import SignalLorenz
5858
from hvcc.generators.ir2c.SignalMath import SignalMath
5959
from hvcc.generators.ir2c.SignalPhasor import SignalPhasor
60+
from hvcc.generators.ir2c.SignalRFFT import SignalRFFT
6061
from hvcc.generators.ir2c.SignalRPole import SignalRPole
6162
from hvcc.generators.ir2c.SignalSample import SignalSample
6263
from hvcc.generators.ir2c.SignalSamphold import SignalSamphold
@@ -97,6 +98,8 @@ class ir2c:
9798
"__tabwrite_stoppable~f": SignalTabwrite,
9899
"__phasor~f": SignalPhasor,
99100
"__phasor_k~f": SignalPhasor,
101+
"__rfft~f": SignalRFFT,
102+
"__rifft~f": SignalRFFT,
100103
"__sample~f": SignalSample,
101104
"__samphold~f": SignalSamphold,
102105
"__slice": ControlSlice,
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* Copyright (c) 2023 Wasted Audio
3+
*
4+
* Permission to use, copy, modify, and/or distribute this software for any
5+
* purpose with or without fee is hereby granted, provided that the above
6+
* copyright notice and this permission notice appear in all copies.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9+
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10+
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11+
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12+
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13+
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14+
* PERFORMANCE OF THIS SOFTWARE.
15+
*/
16+
17+
#include "HvSignalRFFT.h"
18+
#include "pffft.h"
19+
20+
hv_size_t sRFFT_init(SignalRFFT *o, struct HvTable *table, const int size) {
21+
o->table = table;
22+
o->setup = pffft_new_setup(size, PFFFT_REAL);
23+
hv_size_t numBytes = hTable_init(&o->inputs, size);
24+
return numBytes;
25+
}
26+
27+
void sRFFT_free(SignalRFFT *o) {
28+
o->table = NULL;
29+
hTable_free(&o->inputs);
30+
}
31+
32+
void sRFFT_onMessage(HeavyContextInterface *_c, SignalRFFT *o, int letIndex,
33+
const HvMessage *m, void *sendMessage) {
34+
switch (letIndex) {
35+
case 1: {
36+
if (msg_isHashLike(m,0)) {
37+
HvTable *table = hv_table_get(_c, msg_getHash(m,0));
38+
if (table != NULL) {
39+
o->table = table;
40+
if (hTable_getSize(&o->inputs) != hTable_getSize(table)) {
41+
hTable_resize(&o->inputs,
42+
(hv_uint32_t) hv_min_ui(hTable_getSize(&o->inputs), hTable_getSize(table)));
43+
}
44+
}
45+
}
46+
break;
47+
}
48+
case 2: {
49+
if (msg_isFloat(m,0)) {
50+
// rfft size should never exceed the coefficient table size
51+
hTable_resize(&o->inputs, (hv_uint32_t) msg_getFloat(m,0));
52+
}
53+
break;
54+
}
55+
default: return;
56+
}
57+
}
58+
59+
60+
static inline int wrap(const int i, const int n) {
61+
if (i < 0) return (i+n);
62+
if (i >= n) return (i-n);
63+
return i;
64+
}
65+
66+
67+
void __hv_rfft_f(SignalRFFT *o, hv_bInf_t bIn, hv_bOutf_t bOut0, hv_bOutf_t bOut1) {
68+
hv_assert(o->table != NULL);
69+
float *const work = hTable_getBuffer(o->table);
70+
hv_assert(work != NULL);
71+
const int n = hTable_getSize(o->table); // length fir filter
72+
hv_assert((n&HV_N_SIMD_MASK) == 0); // n is a multiple of HV_N_SIMD
73+
74+
float *const inputs = hTable_getBuffer(&o->inputs);
75+
hv_assert(inputs != NULL);
76+
const int m = hTable_getSize(&o->inputs); // length of input buffer.
77+
hv_assert(m >= n);
78+
const int h_orig = hTable_getHead(&o->inputs);
79+
80+
81+
pffft_transform_ordered(o->setup, &bIn, &bOut0, work, PFFFT_FORWARD);
82+
83+
__hv_store_f(inputs+h_orig, bIn); // store the new input to the inputs buffer
84+
hTable_setHead(&o->inputs, wrap(h_orig+HV_N_SIMD, m));
85+
}
86+
87+
88+
void __hv_rifft_f(SignalRFFT *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut) {
89+
hv_assert(o->table != NULL);
90+
float *const work = hTable_getBuffer(o->table);
91+
hv_assert(work != NULL);
92+
const int n = hTable_getSize(o->table); // length fir filter
93+
hv_assert((n&HV_N_SIMD_MASK) == 0); // n is a multiple of HV_N_SIMD
94+
95+
float *const inputs = hTable_getBuffer(&o->inputs);
96+
hv_assert(inputs != NULL);
97+
const int m = hTable_getSize(&o->inputs); // length of input buffer.
98+
hv_assert(m >= n);
99+
const int h_orig = hTable_getHead(&o->inputs);
100+
101+
102+
pffft_transform_ordered(o->setup, &bIn0, &bOut, work, PFFFT_BACKWARD);
103+
104+
__hv_store_f(inputs+h_orig, bIn0); // store the new input to the inputs buffer
105+
hTable_setHead(&o->inputs, wrap(h_orig+HV_N_SIMD, m));
106+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Copyright (c) 2023 Wasted Audio
3+
*
4+
* Permission to use, copy, modify, and/or distribute this software for any
5+
* purpose with or without fee is hereby granted, provided that the above
6+
* copyright notice and this permission notice appear in all copies.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9+
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10+
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11+
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12+
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13+
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14+
* PERFORMANCE OF THIS SOFTWARE.
15+
*/
16+
17+
#ifndef _SIGNAL_RFFT_H_
18+
#define _SIGNAL_RFFT_H_
19+
20+
#include "HvHeavyInternal.h"
21+
#include "pffft.h"
22+
23+
#ifdef __cplusplus
24+
extern "C" {
25+
#endif
26+
27+
#ifdef HV_SIMD_NONE
28+
#define PFFFT_SIMD_DISABLE
29+
#endif
30+
31+
typedef struct SignalRFFT {
32+
struct HvTable *table;
33+
struct HvTable inputs;
34+
struct PFFFT_Setup *setup;
35+
} SignalRFFT;
36+
37+
hv_size_t sRFFT_init(SignalRFFT *o, struct HvTable *coeffs, const int size);
38+
39+
void sRFFT_free(SignalRFFT *o);
40+
41+
void sRFFT_onMessage(HeavyContextInterface *_c, SignalRFFT *o, int letIndex,
42+
const HvMessage *m, void *sendMessage);
43+
44+
void __hv_rfft_f(SignalRFFT *o, hv_bInf_t bIn, hv_bOutf_t bOut0, hv_bOutf_t bOut1);
45+
46+
void __hv_rifft_f(SignalRFFT *o, hv_bInf_t bIn0, hv_bInf_t bIn1, hv_bOutf_t bOut);
47+
48+
#ifdef __cplusplus
49+
} // extern "C"
50+
#endif
51+
52+
#endif // _SIGNAL_RFFT_H_

0 commit comments

Comments
 (0)