gen-rack

Create VCV Rack modules from gen~ exports
Log | Files | Refs | README | LICENSE

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