genlib.cpp (12664B)
1 /******************************************************************************************************************* 2 Cycling '74 License for Max-Generated Code for Export 3 Copyright (c) 2016 Cycling '74 4 The code that Max generates automatically and that end users are capable of exporting and using, and any 5 associated documentation files (the “Software”) is a work of authorship for which Cycling '74 is the author 6 and owner for copyright purposes. A license is hereby granted, free of charge, to any person obtaining a 7 copy of the Software (“Licensee”) to use, copy, modify, merge, publish, and distribute copies of the Software, 8 and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 9 The Software is licensed to Licensee only for non-commercial use. Users who wish to make commercial use of the 10 Software must contact the copyright owner to determine if a license for commercial use is available, and the 11 terms and conditions for same, which may include fees or royalties. For commercial use, please send inquiries 12 to licensing@cycling74.com. The determination of whether a use is commercial use or non-commercial use is based 13 upon the use, not the user. The Software may be used by individuals, institutions, governments, corporations, or 14 other business whether for-profit or non-profit so long as the use itself is not a commercialization of the 15 materials or a use that generates or is intended to generate income, revenue, sales or profit. 16 The above copyright notice and this license shall be included in all copies or substantial portions of the Software. 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 18 THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 20 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 DEALINGS IN THE SOFTWARE. 22 *******************************************************************************************************************/ 23 24 #include "genlib.h" 25 #include "genlib_exportfunctions.h" 26 #include <stdlib.h> // not cstdlib (causes problems with ARM embedded compiler) 27 #include <cstdio> 28 #include <cstring> 29 30 #ifndef MSP_ON_CLANG 31 # include <cmath> 32 #endif 33 34 #ifdef __APPLE__ 35 # include <malloc/malloc.h> 36 #elif !defined(GEN_WINDOWS) // WIN32? 37 # include <malloc.h> 38 # define malloc_size malloc_usable_size 39 #endif 40 41 #ifndef GENLIB_NO_JSON 42 #ifdef MSP_ON_CLANG 43 # include "json.c" 44 # include "json_builder.c" 45 #endif 46 #include "json.h" 47 #include "json_builder.h" 48 #endif 49 50 // DATA_MAXIMUM_ELEMENTS * 8 bytes = 256 mb limit 51 #define DATA_MAXIMUM_ELEMENTS (33554432) 52 53 //////////// export_genlib.cpp //////////// 54 // export version 55 56 void my_memset(void *p, int c, long size); 57 void my_memcpy(void *dst, const void *src, long size); 58 59 t_ptr sysmem_newptr(t_ptr_size size) 60 { 61 return (t_ptr)malloc(size); 62 } 63 64 t_ptr sysmem_newptrclear(t_ptr_size size) 65 { 66 t_ptr p = (t_ptr)malloc(size); 67 68 if (p) 69 my_memset(p, 0, size); 70 71 return p; 72 } 73 74 t_ptr sysmem_resizeptr(void *ptr, t_ptr_size newsize) 75 { 76 return (t_ptr)realloc(ptr, newsize); 77 } 78 79 t_ptr sysmem_resizeptrclear(void *ptr, t_ptr_size newsize) 80 { 81 size_t oldsize = malloc_size(ptr); 82 t_ptr p = (t_ptr)realloc(ptr, newsize); 83 84 if (p) { 85 if (newsize > oldsize) 86 my_memset((char *)p + oldsize, 0, newsize - oldsize); 87 } 88 return p; 89 } 90 91 t_ptr_size sysmem_ptrsize(void *ptr) 92 { 93 return malloc_size(ptr); 94 } 95 96 void sysmem_freeptr(void *ptr) 97 { 98 free(ptr); 99 } 100 101 void sysmem_copyptr(const void *src, void *dst, t_ptr_size bytes) 102 { 103 my_memcpy(dst, src, bytes); 104 } 105 106 void my_memset(void *p, int c, long size) 107 { 108 char *p2 = (char *)p; 109 int i; 110 111 for (i = 0; i < size; i++, p2++) 112 *p2 = char(c); 113 } 114 115 void my_memcpy(void *dst, const void *src, long size) 116 { 117 char *s2 = (char *)src; 118 char *d2 = (char *)dst; 119 int i; 120 121 for (i = 0; i < size; i++, s2++, d2++) 122 *d2 = *s2; 123 } 124 125 void set_zero64(t_sample *memory, long size) 126 { 127 long i; 128 129 for (i = 0; i < size; i++, memory++) { 130 *memory = 0.; 131 } 132 } 133 134 void genlib_report_error(const char *s) 135 { 136 #ifndef GEN_NO_STDLIB 137 fprintf(stderr, "%s\n", s); 138 #endif 139 } 140 141 void genlib_report_message(const char *s) 142 { 143 #ifndef GEN_NO_STDLIB 144 fprintf(stdout, "%s\n", s); 145 #endif 146 } 147 148 unsigned long systime_ticks(void) 149 { 150 return 0; // Gen code can deal with this 151 } 152 153 // NEED THIS FOR WINDOWS: 154 void *operator new(size_t size) { return sysmem_newptr(size); } 155 void *operator new[](size_t size) { return sysmem_newptr(size); } 156 void operator delete(void *p) throw() { sysmem_freeptr(p); } 157 void operator delete[](void *p) throw() { sysmem_freeptr(p); } 158 159 void *genlib_obtain_reference_from_string(const char *name) 160 { 161 return 0; // to be implemented 162 } 163 164 // the rest is stuff to isolate gensym, attrs, atoms, buffers etc. 165 t_genlib_buffer *genlib_obtain_buffer_from_reference(void *ref) 166 { 167 return 0; // to be implemented 168 } 169 170 t_genlib_err genlib_buffer_edit_begin(t_genlib_buffer *b) 171 { 172 return 0; // to be implemented 173 } 174 175 t_genlib_err genlib_buffer_edit_end(t_genlib_buffer *b, long valid) 176 { 177 return 0; // to be implemented 178 } 179 180 t_genlib_err genlib_buffer_getinfo(t_genlib_buffer *b, t_genlib_buffer_info *info) 181 { 182 return 0; // to be implemented 183 } 184 185 char *genlib_reference_getname(void *ref) 186 { 187 return 0; // to be implemented 188 } 189 190 void genlib_buffer_dirty(t_genlib_buffer *b) 191 { 192 // to be implemented 193 } 194 195 t_genlib_err genlib_buffer_perform_begin(t_genlib_buffer *b) 196 { 197 return 0; // to be implemented 198 } 199 void genlib_buffer_perform_end(t_genlib_buffer *b) 200 { 201 // to be implemented 202 } 203 204 t_sample gen_msp_pow(t_sample value, t_sample power) 205 { 206 return pow(value, power); 207 } 208 209 void genlib_data_setbuffer(t_genlib_data *b, void *ref) 210 { 211 genlib_report_error("not supported for export targets\n"); 212 } 213 214 typedef struct { 215 t_genlib_data_info info; 216 t_sample cursor; // used by Delay 217 //t_symbol * name; 218 } t_dsp_gen_data; 219 220 t_genlib_data *genlib_obtain_data_from_reference(void *ref) 221 { 222 t_dsp_gen_data *self = (t_dsp_gen_data *)malloc(sizeof(t_dsp_gen_data)); 223 self->info.dim = 0; 224 self->info.channels = 0; 225 self->info.data = 0; 226 self->cursor = 0; 227 return (t_genlib_data *)self; 228 } 229 230 t_genlib_err genlib_data_getinfo(t_genlib_data *b, t_genlib_data_info *info) 231 { 232 t_dsp_gen_data *self = (t_dsp_gen_data *)b; 233 info->dim = self->info.dim; 234 info->channels = self->info.channels; 235 info->data = self->info.data; 236 return GENLIB_ERR_NONE; 237 } 238 239 void genlib_data_release(t_genlib_data *b) 240 { 241 t_dsp_gen_data *self = (t_dsp_gen_data *)b; 242 243 if (self->info.data) { 244 genlib_sysmem_freeptr(self->info.data); 245 self->info.data = 0; 246 } 247 } 248 249 long genlib_data_getcursor(t_genlib_data *b) 250 { 251 t_dsp_gen_data *self = (t_dsp_gen_data *)b; 252 return long(self->cursor); 253 } 254 255 void genlib_data_setcursor(t_genlib_data *b, long cursor) 256 { 257 t_dsp_gen_data *self = (t_dsp_gen_data *)b; 258 self->cursor = t_sample(cursor); 259 } 260 261 void genlib_data_resize(t_genlib_data *b, long s, long c) 262 { 263 t_dsp_gen_data *self = (t_dsp_gen_data *)b; 264 265 size_t sz, oldsz, copysz; 266 t_sample *old = 0; 267 t_sample *replaced = 0; 268 int i, j, copydim, copychannels, olddim, oldchannels; 269 270 //printf("data resize %d %d\n", s, c); 271 272 // cache old for copying: 273 old = self->info.data; 274 olddim = self->info.dim; 275 oldchannels = self->info.channels; 276 277 // limit [data] size: 278 if (s * c > DATA_MAXIMUM_ELEMENTS) { 279 s = DATA_MAXIMUM_ELEMENTS/c; 280 genlib_report_message("warning: constraining [data] to < 256MB"); 281 } 282 // bytes required: 283 sz = sizeof(t_sample) * s * c; 284 oldsz = sizeof(t_sample) * olddim * oldchannels; 285 286 if (old && sz == oldsz) { 287 // no need to re-allocate, just resize 288 // careful, audio thread may still be using it: 289 if (s > olddim) { 290 self->info.channels = c; 291 self->info.dim = s; 292 } else { 293 self->info.dim = s; 294 self->info.channels = c; 295 } 296 297 set_zero64(self->info.data, s * c); 298 return; 299 300 } else { 301 302 // allocate new: 303 replaced = (t_sample *)sysmem_newptr(sz); 304 305 // check allocation: 306 if (replaced == 0) { 307 genlib_report_error("allocating [data]: out of memory"); 308 // try to reallocate with a default/minimal size instead: 309 if (s > 512 || c > 1) { 310 genlib_data_resize((t_genlib_data *)self, 512, 1); 311 } else { 312 // if this fails, then Max is kaput anyway... 313 genlib_data_resize((t_genlib_data *)self, 4, 1); 314 } 315 return; 316 } 317 318 // fill with zeroes: 319 set_zero64(replaced, s * c); 320 321 // copy in old data: 322 if (old) { 323 // frames to copy: 324 // clamped: 325 copydim = olddim > s ? s : olddim; 326 // use memcpy if channels haven't changed: 327 if (c == oldchannels) { 328 copysz = sizeof(t_sample) * copydim * c; 329 //post("reset resize (same channels) %p %p, %d", self->info.data, old, copysz); 330 memcpy(replaced, old, copysz); 331 } else { 332 // memcpy won't work if channels have changed, 333 // because data is interleaved. 334 // clamp channels copied: 335 copychannels = oldchannels > c ? c : oldchannels; 336 //post("reset resize (different channels) %p %p, %d %d", self->info.data, old, copydim, copychannels); 337 for (i = 0; i < copydim; i++) { 338 for (j = 0; j < copychannels; j++) { 339 replaced[j + i * c] = old[j + i * oldchannels]; 340 } 341 } 342 } 343 } 344 345 // now update info: 346 if (old == 0) { 347 self->info.data = replaced; 348 self->info.dim = s; 349 self->info.channels = c; 350 } else { 351 // need to be careful; the audio thread may still be using it 352 // since dsp_gen_data is preserved through edits 353 // the order of resizing has to be carefully done 354 // to prevent indexing out of bounds 355 // (or maybe I'm being too paranoid here...) 356 if (oldsz > sz) { 357 // shrink size first 358 if (s > olddim) { 359 self->info.channels = c; 360 self->info.dim = s; 361 } else { 362 self->info.dim = s; 363 self->info.channels = c; 364 } 365 self->info.data = replaced; 366 } else { 367 // shrink size after 368 self->info.data = replaced; 369 if (s > olddim) { 370 self->info.channels = c; 371 self->info.dim = s; 372 } else { 373 self->info.dim = s; 374 self->info.channels = c; 375 } 376 } 377 378 // done with old: 379 sysmem_freeptr(old); 380 381 } 382 383 } 384 } 385 386 void genlib_reset_complete(void *data) 387 { 388 } 389 390 #ifndef GENLIB_NO_JSON 391 void genlib_build_json(CommonState *cself, json_value **jsonvalue, getparameter_method getmethod) 392 { 393 int i; 394 395 *jsonvalue = json_object_new(0); 396 397 for (i = 0; i < cself->numparams; i++) { 398 t_param val; 399 400 (getmethod)(cself, i, &val); 401 json_object_push(*jsonvalue, cself->params[i].name, json_double_new(val)); 402 } 403 } 404 405 size_t genlib_getstatesize(CommonState *cself, getparameter_method getmethod) 406 { 407 size_t size; 408 json_value *jsonvalue; 409 410 genlib_build_json(cself, &jsonvalue, getmethod); 411 size = json_measure(jsonvalue); 412 json_builder_free(jsonvalue); 413 414 return size; 415 } 416 417 short genlib_getstate(CommonState *cself, char *state, getparameter_method getmethod) 418 { 419 json_value *jsonvalue; 420 421 genlib_build_json(cself, &jsonvalue, getmethod); 422 json_serialize(state, jsonvalue); 423 json_builder_free(jsonvalue); 424 425 return 0; 426 } 427 428 static void *json_custom_alloc(size_t size, int zero, void *user_data) 429 { 430 return zero ? genlib_sysmem_newptrclear(size) : genlib_sysmem_newptr(size); 431 } 432 433 static void json_custom_free(void *ptr, void *user_data) 434 { 435 genlib_sysmem_freeptr(ptr); 436 } 437 438 short genlib_setstate(CommonState *cself, const char *state, setparameter_method setmethod) 439 { 440 json_settings settings; 441 char error[256]; 442 443 memset(&settings, 0, sizeof(json_settings)); 444 settings.mem_alloc = &json_custom_alloc; 445 settings.mem_free = &json_custom_free; 446 447 json_value *value = json_parse_ex(&settings, state, strlen(state), error); 448 if (value == NULL) 449 return 1; 450 451 if (value->type == json_object) { 452 unsigned int i; 453 for (i = 0; i < value->u.object.length; i++) { 454 char *name = NULL; 455 t_param val = 0; 456 int j; 457 458 if (value->u.object.values[i].value->type == json_double) { 459 name = value->u.object.values[i].name; 460 val = t_param(value->u.object.values[i].value->u.dbl); 461 } else if (value->u.object.values[i].value->type == json_integer) { 462 name = value->u.object.values[i].name; 463 val = t_param(value->u.object.values[i].value->u.integer); 464 } 465 466 if (name) { 467 for (j = 0; j < cself->numparams; j++) { 468 if (!strcmp(cself->params[j].name, name)) { 469 (setmethod)(cself, j, val, NULL); 470 } 471 } 472 } 473 } 474 } 475 476 json_value_free_ex(&settings, value); 477 478 return 0; 479 } 480 #else 481 size_t genlib_getstatesize(CommonState *cself, getparameter_method getmethod) 482 { 483 return 0; 484 } 485 486 short genlib_getstate(CommonState *cself, char *state, getparameter_method getmethod) 487 { 488 return 0; 489 } 490 491 short genlib_setstate(CommonState *cself, const char *state, setparameter_method setmethod) 492 { 493 return 0; 494 } 495 #endif 496