Skip to content

Commit

Permalink
Merge branch 'v0.8.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
dromer committed Aug 7, 2023
2 parents c9c4260 + 63d5960 commit 4243083
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 49 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CHANGELOG
* Pdext: migrate to `pd-lib-builder` and newer `m_pd.h` and add some initial documentation.
* deprecated: Fabric generator - no longer supported
* docs: updates on missing objects and limitations
* bugfix: issues #24, #50, #106
* bugfix: issues #24, #50, #100, #106

0.7.0
-----
Expand Down
1 change: 1 addition & 0 deletions docs/09.supported_vanilla_objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ snapshot~
sqrt~
s~
tabosc4~
tabplay~
tabread4~
tabread~
tabwrite~
Expand Down
1 change: 0 additions & 1 deletion docs/10.unsupported_vanilla_objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ rifft~
scope~
sigmund~
slop~
tabplay~
tabreceive~
tabsend~
threshold~
Expand Down
2 changes: 1 addition & 1 deletion hvcc/core/hv2ir/HIrTabread.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def __init__(
graph: Optional[HeavyGraph] = None,
annotations: Optional[Dict] = None
) -> None:
assert obj_type in {"__tabread~if", "__tabread~f", "__tabreadu~f", "__tabread"}
assert obj_type in {"__tabread~if", "__tabread~f", "__tabread_stoppable~f", "__tabreadu~f", "__tabread"}
super().__init__(obj_type, args=args, graph=graph, annotations=annotations)

def reduce(self) -> Optional[tuple]:
Expand Down
1 change: 1 addition & 0 deletions hvcc/core/hv2ir/HeavyParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ def reduce(self) -> tuple:
"slice": HLangSlice,
"__tabread~if": HIrTabread,
"__tabread~f": HIrTabread,
"__tabread_stoppable~f": HIrTabread,
"__tabreadu~f": HIrTabread,
"__tabread": HIrTabread,
"__tabhead~f": HIrTabhead,
Expand Down
28 changes: 28 additions & 0 deletions hvcc/core/json/heavy.ir.json
Original file line number Diff line number Diff line change
Expand Up @@ -2792,6 +2792,34 @@
"sse": 1
}
},
"__tabread_stoppable~f": {
"inlets": [
"-->",
"-->",
"-->"
],
"ir": {
"control": true,
"signal": true,
"init": true
},
"outlets": [
"~f>",
"-->",
"-->"
],
"args": [{
"default": null,
"value_type": "string",
"name": "table",
"description": "The name of the table to reference.",
"required": true
}],
"perf": {
"avx": 1,
"sse": 1
}
},
"__tabread~if": {
"inlets": [
"~i>",
Expand Down
13 changes: 10 additions & 3 deletions hvcc/generators/ir2c/SignalTabread.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


class SignalTabread(HeavyObject):
"""Handles __tabread~if, __tabread~f, __tabreadu~f
"""Handles __tabread~if, __tabread~f, __tabreadu~f, __tabread_stoppable~f
"""

c_struct = "SignalTabread"
Expand All @@ -44,11 +44,11 @@ def get_C_init(cls, obj_type: str, obj_id: int, args: Dict) -> List[str]:
"sTabread_init(&sTabread_{0}, &hTable_{1}, {2});".format(
obj_id,
args["table_id"],
"true" if obj_type == "__tabread~f" else "false")]
"true" if obj_type in {"__tabread~f", "__tabread_stoppable~f"} else "false")]

@classmethod
def get_C_onMessage(cls, obj_type: str, obj_id: int, inlet_index: int, args: Dict) -> List[str]:
if obj_type in ["__tabread~f", "__tabreadu~f"]:
if obj_type in ["__tabread~f", "__tabreadu~f", "__tabread_stoppable~f"]:
return [
"sTabread_onMessage(_c, &Context(_c)->sTabread_{0}, {1}, m, &sTabread_{0}_sendMessage);".format(
obj_id,
Expand All @@ -71,6 +71,13 @@ def get_C_process(cls, process_dict: Dict, obj_type: str, obj_id: int, args: Dic
process_dict["id"],
", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict["outputBuffers"]])
)]
elif obj_type == "__tabread_stoppable~f":
return [
"__hv_tabread_stoppable_f(this, &sTabread_{0}, {1}, &{2}_{0}_sendMessage);".format(
process_dict["id"],
", ".join([f"VOf({cls._c_buffer(b)})" for b in process_dict["outputBuffers"]]),
cls.preamble
)]
elif obj_type == "__tabreadu~f":
return [
"__hv_tabreadu_f(&sTabread_{0}, {1});".format(
Expand Down
1 change: 1 addition & 0 deletions hvcc/generators/ir2c/ir2c.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class ir2c:
"__tabread~if": SignalTabread,
"__tabread~f": SignalTabread,
"__tabreadu~f": SignalTabread,
"__tabread_stoppable~f": SignalTabread,
"__tabhead~f": SignalTabhead,
"__tabwrite~f": SignalTabwrite,
"__tabwrite_stoppable~f": SignalTabwrite,
Expand Down
32 changes: 31 additions & 1 deletion hvcc/generators/ir2c/static/HvSignalTabread.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
hv_size_t sTabread_init(SignalTabread *o, HvTable *table, bool forceAlignedLoads) {
o->table = table;
o->head = 0;
o->end = hTable_getSize(o->table);
o->forceAlignedLoads = forceAlignedLoads;
o->playing = false;
return 0;
}

Expand All @@ -28,22 +30,35 @@ void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn,
switch (letIn) {
case 0: {
if (o->table != NULL) {
o->end = hTable_getSize(o->table);
switch (msg_getType(m,0)) {
case HV_MSG_BANG: o->head = 0; break;
case HV_MSG_BANG: {
o->head = 0;
o->playing = true;
break;
}
case HV_MSG_FLOAT: {
hv_uint32_t h = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0));
if (msg_getFloat(m,0) < 0.0f) {
// if input is negative, wrap around the end of the table
h = hTable_getSize(o->table) - h;
}
o->head = o->forceAlignedLoads ? (h & ~HV_N_SIMD_MASK) : h;
o->playing = true;

// output new head
HvMessage *n = HV_MESSAGE_ON_STACK(1);
msg_initWithFloat(n, msg_getTimestamp(m), (float) o->head);
sendMessage(_c, 1, n);
break;
}
case HV_MSG_SYMBOL: {
if (msg_compareSymbol(m, 0, "stop")) {
o->head = 0;
o->playing = false;
}
break;
}
default: break;
}
}
Expand All @@ -52,6 +67,21 @@ void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn,
case 1: {
if (msg_isHashLike(m,0)) {
o->table = hv_table_get(_c, msg_getHash(m,0));
o->head = 0;
o->end = hTable_getSize(o->table);
}
break;
}
case 2: {
if (o->table != NULL) {
switch (msg_getType(m,0)) {
case HV_MSG_FLOAT: {
hv_uint32_t e = (hv_uint32_t) hv_abs_f(msg_getFloat(m,0));
o->end = o->head + e;
break;
}
default: break;
}
}
break;
}
Expand Down
83 changes: 42 additions & 41 deletions hvcc/generators/ir2c/static/HvSignalTabread.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ extern "C" {
typedef struct SignalTabread {
HvTable *table; // the table to read
hv_uint32_t head;
hv_uint32_t end;
bool forceAlignedLoads; // false by default, true if using __hv_tabread_f
bool playing; // false by default, only __hv_tabread_stoppable_f may respond to it
} SignalTabread;

// random access to a table
Expand All @@ -43,30 +45,30 @@ static inline void __hv_tabread_if(SignalTabread *o, hv_bIni_t bIn, hv_bOutf_t b
#if HV_SIMD_AVX
const hv_int32_t *const i = (hv_int32_t *) &bIn;

hv_assert(i[0] >= 0 && i[0] < hTable_getAllocated(o->table));
hv_assert(i[1] >= 0 && i[1] < hTable_getAllocated(o->table));
hv_assert(i[2] >= 0 && i[2] < hTable_getAllocated(o->table));
hv_assert(i[3] >= 0 && i[3] < hTable_getAllocated(o->table));
hv_assert(i[4] >= 0 && i[4] < hTable_getAllocated(o->table));
hv_assert(i[5] >= 0 && i[5] < hTable_getAllocated(o->table));
hv_assert(i[6] >= 0 && i[6] < hTable_getAllocated(o->table));
hv_assert(i[7] >= 0 && i[7] < hTable_getAllocated(o->table));
hv_assert(i[0] >= 0 && (hv_uint32_t) i[0] < hTable_getAllocated(o->table));
hv_assert(i[1] >= 0 && (hv_uint32_t) i[1] < hTable_getAllocated(o->table));
hv_assert(i[2] >= 0 && (hv_uint32_t) i[2] < hTable_getAllocated(o->table));
hv_assert(i[3] >= 0 && (hv_uint32_t) i[3] < hTable_getAllocated(o->table));
hv_assert(i[4] >= 0 && (hv_uint32_t) i[4] < hTable_getAllocated(o->table));
hv_assert(i[5] >= 0 && (hv_uint32_t) i[5] < hTable_getAllocated(o->table));
hv_assert(i[6] >= 0 && (hv_uint32_t) i[6] < hTable_getAllocated(o->table));
hv_assert(i[7] >= 0 && (hv_uint32_t) i[7] < hTable_getAllocated(o->table));

*bOut = _mm256_set_ps(b[i[7]], b[i[6]], b[i[5]], b[i[4]], b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
#elif HV_SIMD_SSE
const hv_int32_t *const i = (hv_int32_t *) &bIn;

hv_assert(i[0] >= 0 && ((hv_uint32_t) i[0]) < hTable_getAllocated(o->table));
hv_assert(i[1] >= 0 && ((hv_uint32_t) i[1]) < hTable_getAllocated(o->table));
hv_assert(i[2] >= 0 && ((hv_uint32_t) i[2]) < hTable_getAllocated(o->table));
hv_assert(i[3] >= 0 && ((hv_uint32_t) i[3]) < hTable_getAllocated(o->table));
hv_assert(i[0] >= 0 && (hv_uint32_t) i[0] < hTable_getAllocated(o->table));
hv_assert(i[1] >= 0 && (hv_uint32_t) i[1] < hTable_getAllocated(o->table));
hv_assert(i[2] >= 0 && (hv_uint32_t) i[2] < hTable_getAllocated(o->table));
hv_assert(i[3] >= 0 && (hv_uint32_t) i[3] < hTable_getAllocated(o->table));

*bOut = _mm_set_ps(b[i[3]], b[i[2]], b[i[1]], b[i[0]]);
#elif HV_SIMD_NEON
hv_assert((bIn[0] >= 0) && (bIn[0] < hTable_getAllocated(o->table)));
hv_assert((bIn[1] >= 0) && (bIn[1] < hTable_getAllocated(o->table)));
hv_assert((bIn[2] >= 0) && (bIn[2] < hTable_getAllocated(o->table)));
hv_assert((bIn[3] >= 0) && (bIn[3] < hTable_getAllocated(o->table)));
hv_assert((bIn[0] >= 0) && (hv_uint32_t) bIn[0] < hTable_getAllocated(o->table));
hv_assert((bIn[1] >= 0) && (hv_uint32_t) bIn[1] < hTable_getAllocated(o->table));
hv_assert((bIn[2] >= 0) && (hv_uint32_t) bIn[2] < hTable_getAllocated(o->table));
hv_assert((bIn[3] >= 0) && (hv_uint32_t) bIn[3] < hTable_getAllocated(o->table));

*bOut = (float32x4_t) {b[bIn[0]], b[bIn[1]], b[bIn[2]], b[bIn[3]]};
#else // HV_SIMD_NONE
Expand Down Expand Up @@ -115,36 +117,35 @@ static inline void __hv_tabreadu_f(SignalTabread *o, hv_bOutf_t bOut) {
}

// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
static inline void __hv_tabread_stoppable_f(SignalTabread *o, hv_bOutf_t bOut) {
#if HV_SIMD_AVX
if (o->head == ~0x0) {
*bOut = _mm256_setzero_ps();
} else {
*bOut = _mm256_load_ps(hTable_getBuffer(o->table) + o->head);
o->head += HV_N_SIMD;
static inline void __hv_tabread_stoppable_f(HeavyContextInterface *_c, SignalTabread *o, hv_bOutf_t bOut,
void (*sendMessage)(HeavyContextInterface *, int, const HvMessage *))
{
hv_uint32_t head = o->head;
if (head >= hTable_getAllocated(o->table)) { // stop when we reach the table bounds
o->playing = false;
}
#elif HV_SIMD_SSE
if (o->head == ~0x0) {
*bOut = _mm_setzero_ps();
if (!o->playing) {
__hv_zero_f(bOut); // output silence when not playing
} else {
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + o->head);
o->head += HV_N_SIMD;
}
if (o->end > o->head) { // only play when end is further than play head
#if HV_SIMD_AVX
*bOut = _mm256_loadu_ps(hTable_getBuffer(o->table) + head);
#elif HV_SIMD_SSE
*bOut = _mm_load_ps(hTable_getBuffer(o->table) + head);
#elif HV_SIMD_NEON
if (o->head == ~0x0) {
*bOut = vdupq_n_f32(0.0f);
} else {
*bOut = vld1q_f32(hTable_getBuffer(o->table) + o->head);
o->head += HV_N_SIMD;
}
*bOut = vld1q_f32(hTable_getBuffer(o->table) + head);
#else // HV_SIMD_NONE
if (o->head == ~0x0) {
*bOut = 0.0f;
} else {
*bOut = *(hTable_getBuffer(o->table) + o->head);
o->head += HV_N_SIMD;
}
*bOut = *(hTable_getBuffer(o->table) + head);
#endif
o->head = head + HV_N_SIMD;
} else {
o->playing = false;
__hv_zero_f(bOut); // output silence when not playing
HvMessage *n = HV_MESSAGE_ON_STACK(1);
msg_initWithBang(n, 0);
sendMessage(_c, 2, n);
}
}
}

void sTabread_onMessage(HeavyContextInterface *_c, SignalTabread *o, int letIn, const HvMessage *m,
Expand Down
2 changes: 1 addition & 1 deletion hvcc/generators/ir2c/static/HvSignalTabwrite.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static inline void __hv_tabwriteu_f(SignalTabwrite *o, hv_bInf_t bIn) {
hTable_setHead(o->table, head); // update remote write head
}

// this tabread can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
// this tabwrite can be instructed to stop. It is mainly intended for linear reads that only process a portion of a buffer.
// Stores are unaligned, which can be slow but allows any indicies to be written to.
// TODO(mhroth): this is not stopping!
static inline void __hv_tabwrite_stoppable_f(SignalTabwrite *o, hv_bInf_t bIn) {
Expand Down
69 changes: 69 additions & 0 deletions hvcc/interpreters/pd2hv/libs/pd/tabplay~.pd
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#N canvas 303 459 461 431 10;
#X obj 41 351 outlet~;
#X text 38 375 @hv_arg \$1 table string "" true;
#N canvas 0 22 450 300 @hv_obj 0;
#X obj 146 77 inlet;
#X obj 147 120 outlet;
#X restore 112 150 pd @hv_obj system;
#X msg 112 128 table \$1 size;
#N canvas 0 22 450 300 @hv_obj 0;
#X obj 178 47 inlet;
#X obj 165 128 outlet;
#X restore 43 55 pd @hv_obj slice 1 1;
#N canvas 0 22 450 300 @hv_obj 0;
#X obj 150 61 inlet;
#X obj 147 118 outlet;
#X restore 112 106 pd @hv_obj __var \$1;
#X obj 112 174 - 1;
#X obj 112 80 loadbang -1;
#N canvas 0 23 450 300 @hv_obj 1;
#X obj 169 185 outlet~;
#X obj 249 48 inlet;
#X obj 165 46 inlet;
#X obj 337 48 inlet;
#X obj 306 185 outlet;
#X obj 374 185 outlet;
#X restore 41 327 pd @hv_obj __tabread_stoppable~f \$1;
#X obj 42 7 inlet -->;
#X obj 41 270 max 0;
#X obj 41 297 min 0;
#X msg 253 131 \$1;
#X obj 248 358 outlet;
#N canvas 0 22 450 300 @hv_obj 0;
#X obj 169 24 inlet;
#X obj 273 82 outlet;
#X obj 159 83 outlet;
#X obj 333 82 outlet;
#X obj 212 82 outlet;
#X restore 42 34 pd @hv_obj __switchcase set bang stop;
#X obj 41 221 loadbang 0;
#N canvas 1361 151 307 222 @hv_obj 0;
#X obj 37 37 inlet;
#X obj 40 90 outlet;
#X restore 41 244 pd @hv_obj __var \$1;
#N canvas 0 22 450 300 @hv_obj 0;
#X obj 178 47 inlet;
#X obj 165 128 outlet;
#X restore 287 132 pd @hv_obj slice 1 2;
#X connect 2 0 6 0;
#X connect 3 0 2 0;
#X connect 4 0 8 1;
#X connect 4 0 5 0;
#X connect 5 0 3 0;
#X connect 6 0 11 1;
#X connect 7 0 5 0;
#X connect 8 0 0 0;
#X connect 8 2 13 0;
#X connect 9 0 14 0;
#X connect 10 0 11 0;
#X connect 11 0 8 0;
#X connect 12 0 16 0;
#X connect 14 0 4 0;
#X connect 14 1 16 0;
#X connect 14 1 8 0;
#X connect 14 2 8 0;
#X connect 14 3 12 0;
#X connect 14 3 17 0;
#X connect 15 0 16 0;
#X connect 16 0 10 0;
#X connect 17 0 8 2;

0 comments on commit 4243083

Please sign in to comment.