├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── dependencies └── gen │ ├── genlib.cpp │ ├── genlib.h │ ├── genlib_common.h │ ├── genlib_common_win.h │ ├── genlib_exportfunctions.h │ ├── genlib_ops.h │ ├── genlib_platform.h │ ├── json.c │ ├── json.h │ ├── json_builder.c │ └── json_builder.h ├── include ├── AudioMidiHost.h ├── GenPi.h ├── Globals.h ├── HardwareEncoder.h ├── Host.h ├── Object.h ├── ParameterHost.h ├── Processor.h ├── RtAudioMidiHost.h ├── Settings.h └── gen_exported.h └── src ├── Object.cpp ├── gen_exported.cpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build 3 | build-xcode 4 | 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jsonxx"] 2 | path = dependencies/jsonxx 3 | url = https://github.com/hjiang/jsonxx.git 4 | [submodule "rotaryencoder"] 5 | path = dependencies/rotaryencoder 6 | url = https://github.com/astine/rotaryencoder.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(GenPi) 4 | 5 | message(STATUS "Updating Git Submodules") 6 | execute_process( 7 | COMMAND git submodule update --init --recursive 8 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 9 | ) 10 | 11 | SET(FLOAT_PRECISION "single" CACHE STRING "Floating-point precision (single or double)") 12 | SET(FASTMATH OFF CACHE BOOL "Use approximate math functions") 13 | 14 | find_path(RTAUDIO_INCLUDES "RtAudio.h" HINTS ${CMAKE_FIND_ROOT_PATH}/usr/include/rtaudio ${CMAKE_FIND_ROOT_PATH}/usr/local/include/rtaudio) 15 | if (RTAUDIO_INCLUDES) 16 | file(STRINGS "${RTAUDIO_INCLUDES}/RtAudio.h" RTAUDIO_VERSION_LINE REGEX RTAUDIO_VERSION) 17 | string(REGEX REPLACE "^.*\"(.*)\".*$" "\\1" RTAUDIO_VERSION "${RTAUDIO_VERSION_LINE}") 18 | string(COMPARE LESS "${RTAUDIO_VERSION}" "4.1.0" RTAUDIO_OLD_VERSION) 19 | if (RTAUDIO_OLD_VERSION EQUAL 1) 20 | message(STATUS "RtAudio version ${RTAUDIO_VERSION} is too old. Redefining RtAudioError as RtError") 21 | add_definitions(-DRtAudioError=RtError) 22 | endif() 23 | endif() 24 | 25 | find_path(RTMIDI_INCLUDES "RtMidi.h" HINTS ${CMAKE_FIND_ROOT_PATH}/usr/include/rtmidi ${CMAKE_FIND_ROOT_PATH}/usr/local/include/rtmidi) 26 | if (RTMIDI_INCLUDES) 27 | file(STRINGS "${RTMIDI_INCLUDES}/RtMidi.h" RTMIDI_VERSION_LINE REGEX RTMIDI_VERSION) 28 | string(REGEX REPLACE "^.*\"(.*)\".*$" "\\1" RTMIDI_VERSION "${RTMIDI_VERSION_LINE}") 29 | string(COMPARE LESS "${RTMIDI_VERSION}" "2.1.0" RTMIDI_OLD_VERSION) 30 | if (RTMIDI_OLD_VERSION EQUAL 1) 31 | message(STATUS "RtMidi version ${RTMIDI_VERSION} is too old. Redefining RtMidiError as RtError") 32 | add_definitions(-DRtMidiError=RtError) 33 | endif() 34 | endif() 35 | 36 | include_directories( 37 | "${PROJECT_SOURCE_DIR}/include" 38 | "${PROJECT_SOURCE_DIR}/dependencies/gen" 39 | "${PROJECT_SOURCE_DIR}/dependencies/jsonxx" 40 | "${RTAUDIO_INCLUDES}" 41 | "${RTMIDI_INCLUDES}" 42 | ) 43 | 44 | # file(GLOB_RECURSE PROJECT_HEADERS 45 | 46 | # ) 47 | 48 | if (APPLE) 49 | SET(CMAKE_C_COMPILER clang) 50 | SET(CMAKE_CXX_COMPILER clang++) 51 | set(CMAKE_CXX_FLAGS "-std=c++1y -stdlib=libc++") 52 | else(NOT WIN32) 53 | SET(CMAKE_C_COMPILER gcc) 54 | SET(CMAKE_CXX_COMPILER g++) 55 | set(CMAKE_CXX_FLAGS "-std=c++1y") 56 | endif() 57 | 58 | if (${FLOAT_PRECISION} MATCHES "single") 59 | message(STATUS "Using single-precision floating-point math") 60 | add_definitions(-DGEN_USE_FLOAT32) 61 | elseif (${FLOAT_PRECISION} MATCHES "double") 62 | message(STATUS "Using double-precision floating-point math") 63 | else() 64 | message(FATAL_ERROR "Bad floating-point precision value. Aborting") 65 | endif() 66 | if (FASTMATH) 67 | message(STATUS "Using approximate math functions") 68 | add_definitions(-DGEN_USE_FASTMATH) 69 | endif() 70 | 71 | if (NOT APPLE) 72 | execute_process(COMMAND grep -o BCM2708 /proc/cpuinfo OUTPUT_VARIABLE RASPI) 73 | execute_process(COMMAND grep -o BCM2709 /proc/cpuinfo OUTPUT_VARIABLE RASPI2) # could also be RASPI3 74 | if (RASPI OR RASPI2) 75 | message(STATUS "defining RASPI") 76 | add_definitions(-DRASPI) 77 | set(RASPI_FILES "dependencies/rotaryencoder/rotaryencoder.c") 78 | include_directories( 79 | "${PROJECT_SOURCE_DIR}/dependencies/rotaryencoder" 80 | ) 81 | find_library(WIRINGPI_LIB NAMES wiringPi) 82 | if (NOT WIRINGPI_LIB) 83 | message("\tNot using WiringPi (`apt-get install wiringpi` if you want to)") 84 | else() 85 | add_definitions(-DWIRINGPI) 86 | message("\twiringPi: Don't forget to run ./GenPi as sudo") 87 | endif() 88 | endif() 89 | endif() 90 | 91 | add_executable( ${PROJECT_NAME} 92 | include/GenPi.h 93 | include/RtAudioMidiHost.h 94 | include/Processor.h 95 | include/Host.h 96 | include/Object.h 97 | include/Settings.h 98 | include/AudioMidiHost.h 99 | include/ParameterHost.h 100 | include/HardwareEncoder.h 101 | src/main.cpp 102 | src/Object.cpp 103 | src/gen_exported.cpp 104 | dependencies/gen/genlib.cpp 105 | dependencies/gen/json.c 106 | dependencies/gen/json_builder.c 107 | dependencies/jsonxx/jsonxx.h 108 | dependencies/jsonxx/jsonxx.cc 109 | ${RASPI_FILES} 110 | ${PROJECT_HEADERS} 111 | ) 112 | 113 | # Link RtAudio and it's dependencies 114 | if (APPLE) 115 | find_library(RTAUDIO_LIB "librtaudio_static.a") 116 | target_link_libraries(${PROJECT_NAME} PUBLIC ${RTAUDIO_LIB}) 117 | 118 | find_library(CARBON_LIB "Carbon") 119 | target_link_libraries(${PROJECT_NAME} PUBLIC ${CARBON_LIB}) 120 | 121 | find_library(COREAUDIO_LIB "CoreAudio") 122 | target_link_libraries(${PROJECT_NAME} PUBLIC ${COREAUDIO_LIB}) 123 | else(NOT WIN32) 124 | find_library(RTAUDIO_LIB "rtaudio") 125 | target_link_libraries(${PROJECT_NAME} PUBLIC ${RTAUDIO_LIB}) 126 | endif() 127 | 128 | 129 | # Link RtMidi 130 | if (APPLE) 131 | find_library(RTMIDI_LIB "librtmidi.a") 132 | target_link_libraries(${PROJECT_NAME} PUBLIC ${RTMIDI_LIB}) 133 | 134 | find_library(COREMIDI_LIB "CoreMIDI") 135 | target_link_libraries(${PROJECT_NAME} PUBLIC ${COREMIDI_LIB}) 136 | else(NOT WIN32) 137 | find_library(RTMIDI_LIB "rtmidi") 138 | target_link_libraries(${PROJECT_NAME} PUBLIC ${RTMIDI_LIB}) 139 | endif() 140 | 141 | if (WIRINGPI_LIB) 142 | target_link_libraries(${PROJECT_NAME} PUBLIC wiringPi pthread) 143 | endif() 144 | 145 | UNSET(FLOAT_PRECISION CACHE) 146 | UNSET(FASTMATH CACHE) 147 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Installing genPi 2 | 3 | ## OSX: 4 | 1. get Homebrew 5 | 2. `brew install rt-audio rtmidi` 6 | 3. `cd /path/to/genPi` 7 | 4. `mkdir build-xcode` 8 | 5. `cd build-xcode` 9 | 10 | ### If you want to work in Xcode: 11 | - `cmake .. -G Xcode` 12 | - Open the generated Xcode project (in the build-xcode directory). 13 | 14 | ### If you want to work from the CLI: 15 | - `cmake ..` 16 | - `make` 17 | - `./genPi` 18 | 19 | ## Raspberry Pi 20 | 1. `sudo apt-get install librtaudio-dev librtmidi-dev cmake g++-4.9` 21 | 2. if you want to use wiringPi (for GPIO hardware support), `sudo apt-get install wiringpi` 22 | 3. `cd /path/to/genPi` 23 | 4. `mkdir build` 24 | 5. `cd build` 25 | 6. `cmake ..` 26 | 7. `make` 27 | 8. `./genPi` 28 | 29 | ## Replace genexport.cpp with your own exported code! -------------------------------------------------------------------------------- /dependencies/gen/genlib.cpp: -------------------------------------------------------------------------------- 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 // not cstdlib (causes problems with ARM embedded compiler) 27 | #include 28 | #include 29 | 30 | #ifndef MSP_ON_CLANG 31 | # include 32 | #endif 33 | 34 | #ifdef __APPLE__ 35 | # include 36 | #elif !defined(GEN_WINDOWS) // WIN32? 37 | # include 38 | # define malloc_size malloc_usable_size 39 | #endif 40 | 41 | #ifdef MSP_ON_CLANG 42 | # include "json.c" 43 | # include "json_builder.c" 44 | #endif 45 | #include "json.h" 46 | #include "json_builder.h" 47 | 48 | // DATA_MAXIMUM_ELEMENTS * 8 bytes = 256 mb limit 49 | #define DATA_MAXIMUM_ELEMENTS (33554432) 50 | 51 | //////////// export_genlib.cpp //////////// 52 | // export version 53 | 54 | void my_memset(void *p, int c, long size); 55 | void my_memcpy(void *dst, const void *src, long size); 56 | 57 | t_ptr sysmem_newptr(t_ptr_size size) 58 | { 59 | return (t_ptr)malloc(size); 60 | } 61 | 62 | t_ptr sysmem_newptrclear(t_ptr_size size) 63 | { 64 | t_ptr p = (t_ptr)malloc(size); 65 | 66 | if (p) 67 | my_memset(p, 0, size); 68 | 69 | return p; 70 | } 71 | 72 | t_ptr sysmem_resizeptr(void *ptr, t_ptr_size newsize) 73 | { 74 | return (t_ptr)realloc(ptr, newsize); 75 | } 76 | 77 | t_ptr sysmem_resizeptrclear(void *ptr, t_ptr_size newsize) 78 | { 79 | size_t oldsize = malloc_size(ptr); 80 | t_ptr p = (t_ptr)realloc(ptr, newsize); 81 | 82 | if (p) { 83 | if (newsize > oldsize) 84 | my_memset((char *)p + oldsize, 0, newsize - oldsize); 85 | } 86 | return p; 87 | } 88 | 89 | t_ptr_size sysmem_ptrsize(void *ptr) 90 | { 91 | return malloc_size(ptr); 92 | } 93 | 94 | void sysmem_freeptr(void *ptr) 95 | { 96 | free(ptr); 97 | } 98 | 99 | void sysmem_copyptr(const void *src, void *dst, t_ptr_size bytes) 100 | { 101 | my_memcpy(dst, src, bytes); 102 | } 103 | 104 | void my_memset(void *p, int c, long size) 105 | { 106 | char *p2 = (char *)p; 107 | int i; 108 | 109 | for (i = 0; i < size; i++, p2++) 110 | *p2 = char(c); 111 | } 112 | 113 | void my_memcpy(void *dst, const void *src, long size) 114 | { 115 | char *s2 = (char *)src; 116 | char *d2 = (char *)dst; 117 | int i; 118 | 119 | for (i = 0; i < size; i++, s2++, d2++) 120 | *d2 = *s2; 121 | } 122 | 123 | void set_zero64(t_sample *memory, long size) 124 | { 125 | long i; 126 | 127 | for (i = 0; i < size; i++, memory++) { 128 | *memory = 0.; 129 | } 130 | } 131 | 132 | void genlib_report_error(const char *s) 133 | { 134 | #ifndef GEN_NO_STDLIB 135 | fprintf(stderr, "%s\n", s); 136 | #endif 137 | } 138 | 139 | void genlib_report_message(const char *s) 140 | { 141 | #ifndef GEN_NO_STDLIB 142 | fprintf(stdout, "%s\n", s); 143 | #endif 144 | } 145 | 146 | unsigned long systime_ticks(void) 147 | { 148 | return 0; // Gen code can deal with this 149 | } 150 | 151 | // NEED THIS FOR WINDOWS: 152 | void *operator new(size_t size) { return sysmem_newptr(size); } 153 | void *operator new[](size_t size) { return sysmem_newptr(size); } 154 | void operator delete(void *p) throw() { sysmem_freeptr(p); } 155 | void operator delete[](void *p) throw() { sysmem_freeptr(p); } 156 | 157 | void *genlib_obtain_reference_from_string(const char *name) 158 | { 159 | return 0; // to be implemented 160 | } 161 | 162 | // the rest is stuff to isolate gensym, attrs, atoms, buffers etc. 163 | t_genlib_buffer *genlib_obtain_buffer_from_reference(void *ref) 164 | { 165 | return 0; // to be implemented 166 | } 167 | 168 | t_genlib_err genlib_buffer_edit_begin(t_genlib_buffer *b) 169 | { 170 | return 0; // to be implemented 171 | } 172 | 173 | t_genlib_err genlib_buffer_edit_end(t_genlib_buffer *b, long valid) 174 | { 175 | return 0; // to be implemented 176 | } 177 | 178 | t_genlib_err genlib_buffer_getinfo(t_genlib_buffer *b, t_genlib_buffer_info *info) 179 | { 180 | return 0; // to be implemented 181 | } 182 | 183 | char *genlib_reference_getname(void *ref) 184 | { 185 | return 0; // to be implemented 186 | } 187 | 188 | void genlib_buffer_dirty(t_genlib_buffer *b) 189 | { 190 | // to be implemented 191 | } 192 | 193 | t_genlib_err genlib_buffer_perform_begin(t_genlib_buffer *b) 194 | { 195 | return 0; // to be implemented 196 | } 197 | void genlib_buffer_perform_end(t_genlib_buffer *b) 198 | { 199 | // to be implemented 200 | } 201 | 202 | t_sample gen_msp_pow(t_sample value, t_sample power) 203 | { 204 | return pow(value, power); 205 | } 206 | 207 | void genlib_data_setbuffer(t_genlib_data *b, void *ref) 208 | { 209 | genlib_report_error("not supported for export targets\n"); 210 | } 211 | 212 | typedef struct { 213 | t_genlib_data_info info; 214 | t_sample cursor; // used by Delay 215 | //t_symbol * name; 216 | } t_dsp_gen_data; 217 | 218 | t_genlib_data *genlib_obtain_data_from_reference(void *ref) 219 | { 220 | t_dsp_gen_data *self = (t_dsp_gen_data *)malloc(sizeof(t_dsp_gen_data)); 221 | self->info.dim = 0; 222 | self->info.channels = 0; 223 | self->info.data = 0; 224 | self->cursor = 0; 225 | return (t_genlib_data *)self; 226 | } 227 | 228 | t_genlib_err genlib_data_getinfo(t_genlib_data *b, t_genlib_data_info *info) 229 | { 230 | t_dsp_gen_data *self = (t_dsp_gen_data *)b; 231 | info->dim = self->info.dim; 232 | info->channels = self->info.channels; 233 | info->data = self->info.data; 234 | return GENLIB_ERR_NONE; 235 | } 236 | 237 | void genlib_data_release(t_genlib_data *b) 238 | { 239 | t_dsp_gen_data *self = (t_dsp_gen_data *)b; 240 | 241 | if (self->info.data) { 242 | genlib_sysmem_freeptr(self->info.data); 243 | self->info.data = 0; 244 | } 245 | } 246 | 247 | long genlib_data_getcursor(t_genlib_data *b) 248 | { 249 | t_dsp_gen_data *self = (t_dsp_gen_data *)b; 250 | return long(self->cursor); 251 | } 252 | 253 | void genlib_data_setcursor(t_genlib_data *b, long cursor) 254 | { 255 | t_dsp_gen_data *self = (t_dsp_gen_data *)b; 256 | self->cursor = t_sample(cursor); 257 | } 258 | 259 | void genlib_data_resize(t_genlib_data *b, long s, long c) 260 | { 261 | t_dsp_gen_data *self = (t_dsp_gen_data *)b; 262 | 263 | size_t sz, oldsz, copysz; 264 | t_sample *old = 0; 265 | t_sample *replaced = 0; 266 | int i, j, copydim, copychannels, olddim, oldchannels; 267 | 268 | //printf("data resize %d %d\n", s, c); 269 | 270 | // cache old for copying: 271 | old = self->info.data; 272 | olddim = self->info.dim; 273 | oldchannels = self->info.channels; 274 | 275 | // limit [data] size: 276 | if (s * c > DATA_MAXIMUM_ELEMENTS) { 277 | s = DATA_MAXIMUM_ELEMENTS/c; 278 | genlib_report_message("warning: constraining [data] to < 256MB"); 279 | } 280 | // bytes required: 281 | sz = sizeof(t_sample) * s * c; 282 | oldsz = sizeof(t_sample) * olddim * oldchannels; 283 | 284 | if (old && sz == oldsz) { 285 | // no need to re-allocate, just resize 286 | // careful, audio thread may still be using it: 287 | if (s > olddim) { 288 | self->info.channels = c; 289 | self->info.dim = s; 290 | } else { 291 | self->info.dim = s; 292 | self->info.channels = c; 293 | } 294 | 295 | set_zero64(self->info.data, s * c); 296 | return; 297 | 298 | } else { 299 | 300 | // allocate new: 301 | replaced = (t_sample *)sysmem_newptr(sz); 302 | 303 | // check allocation: 304 | if (replaced == 0) { 305 | genlib_report_error("allocating [data]: out of memory"); 306 | // try to reallocate with a default/minimal size instead: 307 | if (s > 512 || c > 1) { 308 | genlib_data_resize((t_genlib_data *)self, 512, 1); 309 | } else { 310 | // if this fails, then Max is kaput anyway... 311 | genlib_data_resize((t_genlib_data *)self, 4, 1); 312 | } 313 | return; 314 | } 315 | 316 | // fill with zeroes: 317 | set_zero64(replaced, s * c); 318 | 319 | // copy in old data: 320 | if (old) { 321 | // frames to copy: 322 | // clamped: 323 | copydim = olddim > s ? s : olddim; 324 | // use memcpy if channels haven't changed: 325 | if (c == oldchannels) { 326 | copysz = sizeof(t_sample) * copydim * c; 327 | //post("reset resize (same channels) %p %p, %d", self->info.data, old, copysz); 328 | memcpy(replaced, old, copysz); 329 | } else { 330 | // memcpy won't work if channels have changed, 331 | // because data is interleaved. 332 | // clamp channels copied: 333 | copychannels = oldchannels > c ? c : oldchannels; 334 | //post("reset resize (different channels) %p %p, %d %d", self->info.data, old, copydim, copychannels); 335 | for (i = 0; i < copydim; i++) { 336 | for (j = 0; j < copychannels; j++) { 337 | replaced[j + i * c] = old[j + i * oldchannels]; 338 | } 339 | } 340 | } 341 | } 342 | 343 | // now update info: 344 | if (old == 0) { 345 | self->info.data = replaced; 346 | self->info.dim = s; 347 | self->info.channels = c; 348 | } else { 349 | // need to be careful; the audio thread may still be using it 350 | // since dsp_gen_data is preserved through edits 351 | // the order of resizing has to be carefully done 352 | // to prevent indexing out of bounds 353 | // (or maybe I'm being too paranoid here...) 354 | if (oldsz > sz) { 355 | // shrink size first 356 | if (s > olddim) { 357 | self->info.channels = c; 358 | self->info.dim = s; 359 | } else { 360 | self->info.dim = s; 361 | self->info.channels = c; 362 | } 363 | self->info.data = replaced; 364 | } else { 365 | // shrink size after 366 | self->info.data = replaced; 367 | if (s > olddim) { 368 | self->info.channels = c; 369 | self->info.dim = s; 370 | } else { 371 | self->info.dim = s; 372 | self->info.channels = c; 373 | } 374 | } 375 | 376 | // done with old: 377 | sysmem_freeptr(old); 378 | 379 | } 380 | 381 | } 382 | } 383 | 384 | void genlib_reset_complete(void *data) 385 | { 386 | } 387 | 388 | void genlib_build_json(CommonState *cself, json_value **jsonvalue, getparameter_method getmethod) 389 | { 390 | int i; 391 | 392 | *jsonvalue = json_object_new(0); 393 | 394 | for (i = 0; i < cself->numparams; i++) { 395 | t_param val; 396 | 397 | (getmethod)(cself, i, &val); 398 | json_object_push(*jsonvalue, cself->params[i].name, json_double_new(val)); 399 | } 400 | } 401 | 402 | size_t genlib_getstatesize(CommonState *cself, getparameter_method getmethod) 403 | { 404 | size_t size; 405 | json_value *jsonvalue; 406 | 407 | genlib_build_json(cself, &jsonvalue, getmethod); 408 | size = json_measure(jsonvalue); 409 | json_builder_free(jsonvalue); 410 | 411 | return size; 412 | } 413 | 414 | short genlib_getstate(CommonState *cself, char *state, getparameter_method getmethod) 415 | { 416 | json_value *jsonvalue; 417 | 418 | genlib_build_json(cself, &jsonvalue, getmethod); 419 | json_serialize(state, jsonvalue); 420 | json_builder_free(jsonvalue); 421 | 422 | return 0; 423 | } 424 | 425 | static void *json_custom_alloc(size_t size, int zero, void *user_data) 426 | { 427 | return zero ? genlib_sysmem_newptrclear(size) : genlib_sysmem_newptr(size); 428 | } 429 | 430 | static void json_custom_free(void *ptr, void *user_data) 431 | { 432 | genlib_sysmem_freeptr(ptr); 433 | } 434 | 435 | short genlib_setstate(CommonState *cself, const char *state, setparameter_method setmethod) 436 | { 437 | json_settings settings; 438 | char error[256]; 439 | 440 | memset(&settings, 0, sizeof(json_settings)); 441 | settings.mem_alloc = &json_custom_alloc; 442 | settings.mem_free = &json_custom_free; 443 | 444 | json_value *value = json_parse_ex(&settings, state, strlen(state), error); 445 | if (value == NULL) 446 | return 1; 447 | 448 | if (value->type == json_object) { 449 | unsigned int i; 450 | for (i = 0; i < value->u.object.length; i++) { 451 | char *name = NULL; 452 | t_param val = 0; 453 | int j; 454 | 455 | if (value->u.object.values[i].value->type == json_double) { 456 | name = value->u.object.values[i].name; 457 | val = t_param(value->u.object.values[i].value->u.dbl); 458 | } else if (value->u.object.values[i].value->type == json_integer) { 459 | name = value->u.object.values[i].name; 460 | val = t_param(value->u.object.values[i].value->u.integer); 461 | } 462 | 463 | if (name) { 464 | for (j = 0; j < cself->numparams; j++) { 465 | if (!strcmp(cself->params[j].name, name)) { 466 | (setmethod)(cself, j, val, NULL); 467 | } 468 | } 469 | } 470 | } 471 | } 472 | 473 | json_value_free_ex(&settings, value); 474 | 475 | return 0; 476 | } 477 | -------------------------------------------------------------------------------- /dependencies/gen/genlib.h: -------------------------------------------------------------------------------- 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 | #ifndef GENLIB_H 25 | #define GENLIB_H 1 26 | 27 | #include "genlib_common.h" 28 | 29 | //////////// genlib.h //////////// 30 | // genlib.h -- max (gen~) version 31 | 32 | #ifndef GEN_WINDOWS 33 | # ifndef _SIZE_T 34 | # define _SIZE_T 35 | typedef __typeof__(sizeof(int)) size_t; 36 | # endif 37 | #endif 38 | 39 | #ifndef __INT32_TYPE__ 40 | # define __INT32_TYPE__ int 41 | #endif 42 | 43 | #ifdef MSP_ON_CLANG 44 | // gen~ hosted: 45 | typedef unsigned __INT32_TYPE__ uint32_t; 46 | typedef unsigned __INT64_TYPE__ uint64_t; 47 | #else 48 | # ifdef __GNUC__ 49 | # include 50 | # endif 51 | #endif 52 | 53 | #define inf (__DBL_MAX__) 54 | #define GEN_UINT_MAX (4294967295) 55 | #define TWO_TO_32 (4294967296.0) 56 | 57 | #define C74_CONST const 58 | 59 | // max_types.h: 60 | #ifdef C74_X64 61 | typedef unsigned long long t_ptr_uint; 62 | typedef long long t_ptr_int; 63 | typedef double t_atom_float; 64 | typedef t_ptr_uint t_getbytes_size; 65 | #else 66 | typedef unsigned long t_ptr_uint; 67 | typedef long t_ptr_int; 68 | typedef float t_atom_float; 69 | typedef short t_getbytes_size; 70 | #endif // C74_X64 71 | 72 | typedef uint32_t t_uint32; 73 | typedef t_ptr_int t_atom_long; // the type that is an A_LONG in an atom 74 | 75 | typedef t_ptr_int t_int; ///< an integer @ingroup misc 76 | typedef t_ptr_uint t_ptr_size; ///< unsigned pointer-sized value for counting (like size_t) @ingroup misc 77 | typedef t_ptr_int t_atom_long; ///< the type that is an A_LONG in a #t_atom @ingroup misc 78 | typedef t_atom_long t_max_err; ///< an integer value suitable to be returned as an error code @ingroup misc 79 | 80 | extern "C" { 81 | extern t_sample gen_msp_pow (t_sample, t_sample); 82 | 83 | #ifdef MSP_ON_CLANG 84 | // TODO: remove (for debugging only) 85 | //int printf(const char *fmt, ...); 86 | 87 | // math.h: 88 | extern double acos(double); 89 | extern double asin(double); 90 | extern double atan(double); 91 | extern double atan2(double, double); 92 | extern double cos(double); 93 | extern double sin(double); 94 | extern double tan(double); 95 | extern double acosh(double); 96 | extern double asinh(double); 97 | extern double atanh(double); 98 | extern double cosh(double); 99 | extern double sinh(double); 100 | extern double tanh(double); 101 | extern double exp(double); 102 | extern double log(double); 103 | extern double log10(double); 104 | extern double fmod(double, double); 105 | extern double modf(double, double *); 106 | extern double fabs(double); 107 | extern double hypot(double, double); 108 | extern double pow(double, double); 109 | 110 | extern double sqrt(double); 111 | extern double ceil(double); 112 | extern double floor(double); 113 | extern double trunc(double); 114 | extern double round(double); 115 | extern int abs(int); 116 | 117 | extern char *strcpy(char *, const char *); 118 | #else 119 | # include // abs 120 | #endif // MSP_ON_CLANG 121 | 122 | 123 | #if defined(GENLIB_USE_ARMMATH) // ARM embedded support 124 | # include "arm_math.h" 125 | # define sin(x) arm_sin_f32(x) 126 | # define sinf(x) arm_sin_f32(x) 127 | # define cos(x) arm_cos_f32(x) 128 | # define cosf(x) arm_cos_f32(x) 129 | # define sqrt(x) arm_sqrtf(x) 130 | # define sqrtf(x) arm_sqrtf(x) 131 | # define rand(...) arm_rand32() 132 | # undef RAND_MAX 133 | # define RAND_MAX UINT32_MAX 134 | #endif // GENLIB_USE_ARMMATH 135 | 136 | #if defined(GENLIB_USE_FASTMATH) 137 | # include 138 | # define tan(x) fastertanfull(x) 139 | # define exp(x) fasterexp(x) 140 | # define log2(x) fasterlog2(x) 141 | # define pow(x,y) fasterpow(x,y) 142 | # define pow2(x) fasterpow2(x) 143 | # define atan2(x,y) fasteratan2(x,y) 144 | # define tanh(x) fastertanh(x) 145 | # if !defined(GENLIB_USE_ARMMATH) 146 | # define sin(x) fastersinfull(x); 147 | # define cos(x) fastercosfull(x); 148 | # endif 149 | #endif // GENLIB_USE_FASTMATH 150 | 151 | // string reference handling: 152 | void *genlib_obtain_reference_from_string(const char *name); 153 | char *genlib_reference_getname(void *ref); 154 | 155 | // buffer handling: 156 | t_genlib_buffer *genlib_obtain_buffer_from_reference(void *ref); 157 | t_genlib_err genlib_buffer_edit_begin(t_genlib_buffer *b); 158 | t_genlib_err genlib_buffer_edit_end(t_genlib_buffer *b, long valid); 159 | t_genlib_err genlib_buffer_getinfo(t_genlib_buffer *b, t_genlib_buffer_info *info); 160 | void genlib_buffer_dirty(t_genlib_buffer *b); 161 | t_genlib_err genlib_buffer_perform_begin(t_genlib_buffer *b); 162 | void genlib_buffer_perform_end(t_genlib_buffer *b); 163 | 164 | // data handling: 165 | t_genlib_data *genlib_obtain_data_from_reference(void *ref); 166 | t_genlib_err genlib_data_getinfo(t_genlib_data *b, t_genlib_data_info *info); 167 | void genlib_data_resize(t_genlib_data *b, long dim, long channels); 168 | void genlib_data_setbuffer(t_genlib_data *b, void *ref); 169 | void genlib_data_release(t_genlib_data *b); 170 | void genlib_data_setcursor(t_genlib_data *b, long cursor); 171 | long genlib_data_getcursor(t_genlib_data *b); 172 | 173 | // other notification: 174 | void genlib_reset_complete(void *data); 175 | 176 | // get/set state of parameters 177 | size_t genlib_getstatesize(CommonState *cself, getparameter_method getmethod); 178 | short genlib_getstate(CommonState *cself, char *state, getparameter_method getmethod); 179 | short genlib_setstate(CommonState *cself, const char *state, setparameter_method setmethod); 180 | 181 | }; // extern "C" 182 | 183 | #define genlib_sysmem_newptr(s) sysmem_newptr(s) 184 | #define genlib_sysmem_newptrclear(s) sysmem_newptrclear(s) 185 | #define genlib_sysmem_resizeptr(p, s) sysmem_resizeptr(p, s) 186 | #define genlib_sysmem_resizeptrclear(p, s) sysmem_resizeptrclear(p, s) 187 | #define genlib_sysmem_ptrsize(p) sysmem_ptrsize(p) 188 | #define genlib_sysmem_freeptr(p) sysmem_freeptr(p) 189 | #define genlib_sysmem_copyptr(s, d, b) sysmem_copyptr(s, d, b) 190 | #define genlib_set_zero64(d, n) set_zero64(d, n) 191 | #define genlib_ticks systime_ticks 192 | 193 | #endif // GENLIB_H 194 | -------------------------------------------------------------------------------- /dependencies/gen/genlib_common.h: -------------------------------------------------------------------------------- 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 | #ifndef GENLIB_COMMON_H 25 | #define GENLIB_COMMON_H 1 26 | 27 | #include "genlib_platform.h" 28 | 29 | //////////// genlib_common.h //////////// 30 | // common data structure header file -- this is the stuff required by the 31 | // common code and accessed by the export and max code 32 | 33 | #define DSP_GEN_MAX_SIGNALS 16 34 | 35 | #ifdef GENLIB_USE_FLOAT32 36 | typedef float t_sample; 37 | typedef float t_param; 38 | #else 39 | typedef double t_sample; 40 | typedef double t_param; 41 | #endif 42 | typedef char *t_ptr; 43 | 44 | typedef long t_genlib_err; 45 | typedef enum { 46 | GENLIB_ERR_NONE = 0, ///< No error 47 | GENLIB_ERR_GENERIC = -1, ///< Generic error 48 | GENLIB_ERR_INVALID_PTR = -2, ///< Invalid Pointer 49 | GENLIB_ERR_DUPLICATE = -3, ///< Duplicate 50 | GENLIB_ERR_OUT_OF_MEM = -4, ///< Out of memory 51 | 52 | GENLIB_ERR_LOOP_OVERFLOW = 100, // too many iterations of loops in perform() 53 | GENLIB_ERR_NULL_BUFFER = 101 // missing signal data in perform() 54 | 55 | } e_genlib_errorcodes; 56 | 57 | typedef enum { 58 | GENLIB_PARAMTYPE_FLOAT = 0, 59 | GENLIB_PARAMTYPE_SYM = 1 60 | } e_genlib_paramtypes; 61 | 62 | struct ParamInfo 63 | { 64 | t_param defaultvalue; 65 | void *defaultref; 66 | char hasinputminmax; 67 | char hasminmax; 68 | t_param inputmin, inputmax; 69 | t_param outputmin, outputmax; 70 | const char *name; 71 | const char *units; 72 | int paramtype; // 0 -> float64, 1 -> symbol (table name) 73 | t_param exp; // future, for scaling 74 | }; 75 | 76 | struct CommonState 77 | { 78 | t_sample sr; 79 | int vs; 80 | int numins; 81 | int numouts; 82 | const char **inputnames; 83 | const char **outputnames; 84 | int numparams; 85 | ParamInfo *params; 86 | 87 | void *parammap; // implementation-dependent 88 | void *api; // implementation-dependent 89 | }; 90 | 91 | // opaque interface to float32 buffer: 92 | typedef struct _genlib_buffer t_genlib_buffer; 93 | typedef struct { 94 | char b_name[256]; ///< name of the buffer 95 | float *b_samples; ///< stored with interleaved channels if multi-channel 96 | long b_frames; ///< number of sample frames (each one is sizeof(float) * b_nchans bytes) 97 | long b_nchans; ///< number of channels 98 | long b_size; ///< size of buffer in floats 99 | float b_sr; ///< sampling rate of the buffer 100 | long b_modtime; ///< last modified time ("dirty" method) 101 | long b_rfu[57]; ///< reserved for future use 102 | } t_genlib_buffer_info; 103 | 104 | // opaque interface to float64 buffer: 105 | typedef struct _genlib_data t_genlib_data; 106 | typedef struct { 107 | int dim, channels; 108 | t_sample * data; 109 | } t_genlib_data_info; 110 | 111 | typedef void (*setparameter_method) (CommonState *, long, t_param, void *); 112 | typedef void (*getparameter_method) (CommonState *, long, t_param *); 113 | 114 | #endif // GENLIB_COMMON_H 115 | 116 | 117 | -------------------------------------------------------------------------------- /dependencies/gen/genlib_common_win.h: -------------------------------------------------------------------------------- 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 | #ifndef GENLIB_COMMON_WIN_H 25 | #define GENLIB_COMMON_WIN_H 26 | 27 | #ifdef _MSC_VER 28 | #define GEN_WINDOWS 29 | #endif 30 | 31 | #ifdef GEN_WINDOWS 32 | 33 | #include 34 | #include 35 | 36 | typedef __int32 int32_t; 37 | typedef unsigned __int32 uint32_t; 38 | typedef __int64 int64_t; 39 | typedef unsigned __int64 uint64_t; 40 | #define malloc_size _msize 41 | 42 | #define __DBL_EPSILON__ (DBL_EPSILON) 43 | 44 | #endif 45 | 46 | #endif 47 | 48 | -------------------------------------------------------------------------------- /dependencies/gen/genlib_exportfunctions.h: -------------------------------------------------------------------------------- 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 | #ifndef GENLIB_EXPORT_FUNCTIONS_H 25 | #define GENLIB_EXPORT_FUNCTIONS_H 1 26 | 27 | typedef char *t_ptr; 28 | 29 | t_ptr sysmem_newptr(t_ptr_size size); 30 | t_ptr sysmem_newptrclear(t_ptr_size size); 31 | t_ptr sysmem_resizeptr(void *ptr, t_ptr_size newsize); 32 | t_ptr sysmem_resizeptrclear(void *ptr, t_ptr_size newsize); 33 | t_ptr_size sysmem_ptrsize(void *ptr); 34 | void sysmem_freeptr(void *ptr); 35 | void sysmem_copyptr(const void *src, void *dst, t_ptr_size bytes); 36 | unsigned long systime_ticks(void); 37 | 38 | void genlib_report_error(const char *s); 39 | void genlib_report_message(const char *s); 40 | void set_zero64(t_sample *mem, long size); 41 | 42 | #endif // GENLIB_EXPORT_FUNCTIONS_H 43 | -------------------------------------------------------------------------------- /dependencies/gen/genlib_platform.h: -------------------------------------------------------------------------------- 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 | #ifndef GENLIB_PLATFORM_H 25 | #define GENLIB_PLATFORM_H 1 26 | 27 | #include "genlib_common_win.h" 28 | 29 | #if defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7) // embedded ARM cortex support 30 | #define GENLIB_NO_STDLIB 31 | #define GENLIB_USE_ARMMATH 32 | #define GENLIB_USE_FASTMATH 33 | #endif // defined(ARM_MATH_CM4) || defined(ARM_MATH_CM7) 34 | 35 | #if defined (__arm__) // general ARM support 36 | #define GENLIB_USE_FLOAT32 37 | #endif 38 | 39 | 40 | 41 | #endif // ifdef GENLIB_PLATFORM_H -------------------------------------------------------------------------------- /dependencies/gen/json.c: -------------------------------------------------------------------------------- 1 | /* vim: set et ts=3 sw=3 sts=3 ft=c: 2 | * 3 | * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. 4 | * https://github.com/udp/json-parser 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | #include "json.h" 31 | 32 | #ifdef _MSC_VER 33 | #ifndef _CRT_SECURE_NO_WARNINGS 34 | #define _CRT_SECURE_NO_WARNINGS 35 | #endif 36 | #endif 37 | 38 | const struct _json_value json_value_none; 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | typedef unsigned int json_uchar; 46 | 47 | static unsigned char hex_value (json_char c) 48 | { 49 | if (isdigit(c)) 50 | return c - '0'; 51 | 52 | switch (c) { 53 | case 'a': case 'A': return 0x0A; 54 | case 'b': case 'B': return 0x0B; 55 | case 'c': case 'C': return 0x0C; 56 | case 'd': case 'D': return 0x0D; 57 | case 'e': case 'E': return 0x0E; 58 | case 'f': case 'F': return 0x0F; 59 | default: return 0xFF; 60 | } 61 | } 62 | 63 | typedef struct 64 | { 65 | unsigned long used_memory; 66 | 67 | unsigned int uint_max; 68 | unsigned long ulong_max; 69 | 70 | json_settings settings; 71 | int first_pass; 72 | 73 | const json_char * ptr; 74 | unsigned int cur_line, cur_col; 75 | 76 | } json_state; 77 | 78 | static void * default_alloc (size_t size, int zero, void * user_data) 79 | { 80 | return zero ? calloc (1, size) : malloc (size); 81 | } 82 | 83 | static void default_free (void * ptr, void * user_data) 84 | { 85 | free (ptr); 86 | } 87 | 88 | static void * json_alloc (json_state * state, unsigned long size, int zero) 89 | { 90 | if ((state->ulong_max - state->used_memory) < size) 91 | return 0; 92 | 93 | if (state->settings.max_memory 94 | && (state->used_memory += size) > state->settings.max_memory) 95 | { 96 | return 0; 97 | } 98 | 99 | return state->settings.mem_alloc (size, zero, state->settings.user_data); 100 | } 101 | 102 | static int new_value (json_state * state, 103 | json_value ** top, json_value ** root, json_value ** alloc, 104 | json_type type) 105 | { 106 | json_value * value; 107 | int values_size; 108 | 109 | if (!state->first_pass) 110 | { 111 | value = *top = *alloc; 112 | *alloc = (*alloc)->_reserved.next_alloc; 113 | 114 | if (!*root) 115 | *root = value; 116 | 117 | switch (value->type) 118 | { 119 | case json_array: 120 | 121 | if (value->u.array.length == 0) 122 | break; 123 | 124 | if (! (value->u.array.values = (json_value **) json_alloc 125 | (state, value->u.array.length * sizeof (json_value *), 0)) ) 126 | { 127 | return 0; 128 | } 129 | 130 | value->u.array.length = 0; 131 | break; 132 | 133 | case json_object: 134 | 135 | if (value->u.object.length == 0) 136 | break; 137 | 138 | values_size = sizeof (*value->u.object.values) * value->u.object.length; 139 | 140 | if (! (value->u.object.values = (json_object_entry *) json_alloc 141 | (state, values_size + ((unsigned long) value->u.object.values), 0)) ) 142 | { 143 | return 0; 144 | } 145 | 146 | value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; 147 | 148 | value->u.object.length = 0; 149 | break; 150 | 151 | case json_string: 152 | 153 | if (! (value->u.string.ptr = (json_char *) json_alloc 154 | (state, (value->u.string.length + 1) * sizeof (json_char), 0)) ) 155 | { 156 | return 0; 157 | } 158 | 159 | value->u.string.length = 0; 160 | break; 161 | 162 | default: 163 | break; 164 | }; 165 | 166 | return 1; 167 | } 168 | 169 | if (! (value = (json_value *) json_alloc 170 | (state, sizeof (json_value) + state->settings.value_extra, 1))) 171 | { 172 | return 0; 173 | } 174 | 175 | if (!*root) 176 | *root = value; 177 | 178 | value->type = type; 179 | value->parent = *top; 180 | 181 | #ifdef JSON_TRACK_SOURCE 182 | value->line = state->cur_line; 183 | value->col = state->cur_col; 184 | #endif 185 | 186 | if (*alloc) 187 | (*alloc)->_reserved.next_alloc = value; 188 | 189 | *alloc = *top = value; 190 | 191 | return 1; 192 | } 193 | 194 | #define whitespace \ 195 | case '\n': ++ state.cur_line; state.cur_col = 0; \ 196 | case ' ': case '\t': case '\r' 197 | 198 | #define string_add(b) \ 199 | do { if (!state.first_pass) string [string_length] = b; ++ string_length; } while (0); 200 | 201 | #define line_and_col \ 202 | state.cur_line, state.cur_col 203 | 204 | static const long 205 | flag_next = 1 << 0, 206 | flag_reproc = 1 << 1, 207 | flag_need_comma = 1 << 2, 208 | flag_seek_value = 1 << 3, 209 | flag_escaped = 1 << 4, 210 | flag_string = 1 << 5, 211 | flag_need_colon = 1 << 6, 212 | flag_done = 1 << 7, 213 | flag_num_negative = 1 << 8, 214 | flag_num_zero = 1 << 9, 215 | flag_num_e = 1 << 10, 216 | flag_num_e_got_sign = 1 << 11, 217 | flag_num_e_negative = 1 << 12, 218 | flag_line_comment = 1 << 13, 219 | flag_block_comment = 1 << 14; 220 | 221 | json_value * json_parse_ex (json_settings * settings, 222 | const json_char * json, 223 | size_t length, 224 | char * error_buf) 225 | { 226 | json_char error [json_error_max]; 227 | const json_char * end; 228 | json_value * top, * root, * alloc = 0; 229 | json_state state = { 0 }; 230 | long flags; 231 | long num_digits = 0, num_e = 0; 232 | json_int_t num_fraction = 0; 233 | 234 | /* Skip UTF-8 BOM 235 | */ 236 | if (length >= 3 && ((unsigned char) json [0]) == 0xEF 237 | && ((unsigned char) json [1]) == 0xBB 238 | && ((unsigned char) json [2]) == 0xBF) 239 | { 240 | json += 3; 241 | length -= 3; 242 | } 243 | 244 | error[0] = '\0'; 245 | end = (json + length); 246 | 247 | memcpy (&state.settings, settings, sizeof (json_settings)); 248 | 249 | if (!state.settings.mem_alloc) 250 | state.settings.mem_alloc = default_alloc; 251 | 252 | if (!state.settings.mem_free) 253 | state.settings.mem_free = default_free; 254 | 255 | memset (&state.uint_max, 0xFF, sizeof (state.uint_max)); 256 | memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); 257 | 258 | state.uint_max -= 8; /* limit of how much can be added before next check */ 259 | state.ulong_max -= 8; 260 | 261 | for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass) 262 | { 263 | json_uchar uchar; 264 | unsigned char uc_b1, uc_b2, uc_b3, uc_b4; 265 | json_char * string = 0; 266 | unsigned int string_length = 0; 267 | 268 | top = root = 0; 269 | flags = flag_seek_value; 270 | 271 | state.cur_line = 1; 272 | 273 | for (state.ptr = json ;; ++ state.ptr) 274 | { 275 | json_char b = (state.ptr == end ? 0 : *state.ptr); 276 | 277 | if (flags & flag_string) 278 | { 279 | if (!b) 280 | { sprintf (error, "Unexpected EOF in string (at %d:%d)", line_and_col); 281 | goto e_failed; 282 | } 283 | 284 | if (string_length > state.uint_max) 285 | goto e_overflow; 286 | 287 | if (flags & flag_escaped) 288 | { 289 | flags &= ~ flag_escaped; 290 | 291 | switch (b) 292 | { 293 | case 'b': string_add ('\b'); break; 294 | case 'f': string_add ('\f'); break; 295 | case 'n': string_add ('\n'); break; 296 | case 'r': string_add ('\r'); break; 297 | case 't': string_add ('\t'); break; 298 | case 'u': 299 | 300 | if (end - state.ptr < 4 || 301 | (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || 302 | (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || 303 | (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || 304 | (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) 305 | { 306 | sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); 307 | goto e_failed; 308 | } 309 | 310 | uc_b1 = (uc_b1 << 4) | uc_b2; 311 | uc_b2 = (uc_b3 << 4) | uc_b4; 312 | uchar = (uc_b1 << 8) | uc_b2; 313 | 314 | if ((uchar & 0xF800) == 0xD800) { 315 | json_uchar uchar2; 316 | 317 | if (end - state.ptr < 6 || (*++ state.ptr) != '\\' || (*++ state.ptr) != 'u' || 318 | (uc_b1 = hex_value (*++ state.ptr)) == 0xFF || 319 | (uc_b2 = hex_value (*++ state.ptr)) == 0xFF || 320 | (uc_b3 = hex_value (*++ state.ptr)) == 0xFF || 321 | (uc_b4 = hex_value (*++ state.ptr)) == 0xFF) 322 | { 323 | sprintf (error, "Invalid character value `%c` (at %d:%d)", b, line_and_col); 324 | goto e_failed; 325 | } 326 | 327 | uc_b1 = (uc_b1 << 4) | uc_b2; 328 | uc_b2 = (uc_b3 << 4) | uc_b4; 329 | uchar2 = (uc_b1 << 8) | uc_b2; 330 | 331 | uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); 332 | } 333 | 334 | if (sizeof (json_char) >= sizeof (json_uchar) || (uchar <= 0x7F)) 335 | { 336 | string_add ((json_char) uchar); 337 | break; 338 | } 339 | 340 | if (uchar <= 0x7FF) 341 | { 342 | if (state.first_pass) 343 | string_length += 2; 344 | else 345 | { string [string_length ++] = 0xC0 | (uchar >> 6); 346 | string [string_length ++] = 0x80 | (uchar & 0x3F); 347 | } 348 | 349 | break; 350 | } 351 | 352 | if (uchar <= 0xFFFF) { 353 | if (state.first_pass) 354 | string_length += 3; 355 | else 356 | { string [string_length ++] = 0xE0 | (uchar >> 12); 357 | string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); 358 | string [string_length ++] = 0x80 | (uchar & 0x3F); 359 | } 360 | 361 | break; 362 | } 363 | 364 | if (state.first_pass) 365 | string_length += 4; 366 | else 367 | { string [string_length ++] = 0xF0 | (uchar >> 18); 368 | string [string_length ++] = 0x80 | ((uchar >> 12) & 0x3F); 369 | string [string_length ++] = 0x80 | ((uchar >> 6) & 0x3F); 370 | string [string_length ++] = 0x80 | (uchar & 0x3F); 371 | } 372 | 373 | break; 374 | 375 | default: 376 | string_add (b); 377 | }; 378 | 379 | continue; 380 | } 381 | 382 | if (b == '\\') 383 | { 384 | flags |= flag_escaped; 385 | continue; 386 | } 387 | 388 | if (b == '"') 389 | { 390 | if (!state.first_pass) 391 | string [string_length] = 0; 392 | 393 | flags &= ~ flag_string; 394 | string = 0; 395 | 396 | switch (top->type) 397 | { 398 | case json_string: 399 | 400 | top->u.string.length = string_length; 401 | flags |= flag_next; 402 | 403 | break; 404 | 405 | case json_object: 406 | 407 | if (state.first_pass) 408 | (*(json_char **) &top->u.object.values) += string_length + 1; 409 | else 410 | { 411 | top->u.object.values [top->u.object.length].name 412 | = (json_char *) top->_reserved.object_mem; 413 | 414 | top->u.object.values [top->u.object.length].name_length 415 | = string_length; 416 | 417 | (*(json_char **) &top->_reserved.object_mem) += string_length + 1; 418 | } 419 | 420 | flags |= flag_seek_value | flag_need_colon; 421 | continue; 422 | 423 | default: 424 | break; 425 | }; 426 | } 427 | else 428 | { 429 | string_add (b); 430 | continue; 431 | } 432 | } 433 | 434 | if (state.settings.settings & json_enable_comments) 435 | { 436 | if (flags & (flag_line_comment | flag_block_comment)) 437 | { 438 | if (flags & flag_line_comment) 439 | { 440 | if (b == '\r' || b == '\n' || !b) 441 | { 442 | flags &= ~ flag_line_comment; 443 | -- state.ptr; /* so null can be reproc'd */ 444 | } 445 | 446 | continue; 447 | } 448 | 449 | if (flags & flag_block_comment) 450 | { 451 | if (!b) 452 | { sprintf (error, "%d:%d: Unexpected EOF in block comment", line_and_col); 453 | goto e_failed; 454 | } 455 | 456 | if (b == '*' && state.ptr < (end - 1) && state.ptr [1] == '/') 457 | { 458 | flags &= ~ flag_block_comment; 459 | ++ state.ptr; /* skip closing sequence */ 460 | } 461 | 462 | continue; 463 | } 464 | } 465 | else if (b == '/') 466 | { 467 | if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) 468 | { sprintf (error, "%d:%d: Comment not allowed here", line_and_col); 469 | goto e_failed; 470 | } 471 | 472 | if (++ state.ptr == end) 473 | { sprintf (error, "%d:%d: EOF unexpected", line_and_col); 474 | goto e_failed; 475 | } 476 | 477 | switch (b = *state.ptr) 478 | { 479 | case '/': 480 | flags |= flag_line_comment; 481 | continue; 482 | 483 | case '*': 484 | flags |= flag_block_comment; 485 | continue; 486 | 487 | default: 488 | sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", line_and_col, b); 489 | goto e_failed; 490 | }; 491 | } 492 | } 493 | 494 | if (flags & flag_done) 495 | { 496 | if (!b) 497 | break; 498 | 499 | switch (b) 500 | { 501 | whitespace: 502 | continue; 503 | 504 | default: 505 | 506 | sprintf (error, "%d:%d: Trailing garbage: `%c`", 507 | state.cur_line, state.cur_col, b); 508 | 509 | goto e_failed; 510 | }; 511 | } 512 | 513 | if (flags & flag_seek_value) 514 | { 515 | switch (b) 516 | { 517 | whitespace: 518 | continue; 519 | 520 | case ']': 521 | 522 | if (top && top->type == json_array) 523 | flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; 524 | else 525 | { sprintf (error, "%d:%d: Unexpected ]", line_and_col); 526 | goto e_failed; 527 | } 528 | 529 | break; 530 | 531 | default: 532 | 533 | if (flags & flag_need_comma) 534 | { 535 | if (b == ',') 536 | { flags &= ~ flag_need_comma; 537 | continue; 538 | } 539 | else 540 | { 541 | sprintf (error, "%d:%d: Expected , before %c", 542 | state.cur_line, state.cur_col, b); 543 | 544 | goto e_failed; 545 | } 546 | } 547 | 548 | if (flags & flag_need_colon) 549 | { 550 | if (b == ':') 551 | { flags &= ~ flag_need_colon; 552 | continue; 553 | } 554 | else 555 | { 556 | sprintf (error, "%d:%d: Expected : before %c", 557 | state.cur_line, state.cur_col, b); 558 | 559 | goto e_failed; 560 | } 561 | } 562 | 563 | flags &= ~ flag_seek_value; 564 | 565 | switch (b) 566 | { 567 | case '{': 568 | 569 | if (!new_value (&state, &top, &root, &alloc, json_object)) 570 | goto e_alloc_failure; 571 | 572 | continue; 573 | 574 | case '[': 575 | 576 | if (!new_value (&state, &top, &root, &alloc, json_array)) 577 | goto e_alloc_failure; 578 | 579 | flags |= flag_seek_value; 580 | continue; 581 | 582 | case '"': 583 | 584 | if (!new_value (&state, &top, &root, &alloc, json_string)) 585 | goto e_alloc_failure; 586 | 587 | flags |= flag_string; 588 | 589 | string = top->u.string.ptr; 590 | string_length = 0; 591 | 592 | continue; 593 | 594 | case 't': 595 | 596 | if ((end - state.ptr) < 3 || *(++ state.ptr) != 'r' || 597 | *(++ state.ptr) != 'u' || *(++ state.ptr) != 'e') 598 | { 599 | goto e_unknown_value; 600 | } 601 | 602 | if (!new_value (&state, &top, &root, &alloc, json_boolean)) 603 | goto e_alloc_failure; 604 | 605 | top->u.boolean = 1; 606 | 607 | flags |= flag_next; 608 | break; 609 | 610 | case 'f': 611 | 612 | if ((end - state.ptr) < 4 || *(++ state.ptr) != 'a' || 613 | *(++ state.ptr) != 'l' || *(++ state.ptr) != 's' || 614 | *(++ state.ptr) != 'e') 615 | { 616 | goto e_unknown_value; 617 | } 618 | 619 | if (!new_value (&state, &top, &root, &alloc, json_boolean)) 620 | goto e_alloc_failure; 621 | 622 | flags |= flag_next; 623 | break; 624 | 625 | case 'n': 626 | 627 | if ((end - state.ptr) < 3 || *(++ state.ptr) != 'u' || 628 | *(++ state.ptr) != 'l' || *(++ state.ptr) != 'l') 629 | { 630 | goto e_unknown_value; 631 | } 632 | 633 | if (!new_value (&state, &top, &root, &alloc, json_null)) 634 | goto e_alloc_failure; 635 | 636 | flags |= flag_next; 637 | break; 638 | 639 | default: 640 | 641 | if (isdigit (b) || b == '-') 642 | { 643 | if (!new_value (&state, &top, &root, &alloc, json_integer)) 644 | goto e_alloc_failure; 645 | 646 | if (!state.first_pass) 647 | { 648 | while (isdigit (b) || b == '+' || b == '-' 649 | || b == 'e' || b == 'E' || b == '.') 650 | { 651 | if ( (++ state.ptr) == end) 652 | { 653 | b = 0; 654 | break; 655 | } 656 | 657 | b = *state.ptr; 658 | } 659 | 660 | flags |= flag_next | flag_reproc; 661 | break; 662 | } 663 | 664 | flags &= ~ (flag_num_negative | flag_num_e | 665 | flag_num_e_got_sign | flag_num_e_negative | 666 | flag_num_zero); 667 | 668 | num_digits = 0; 669 | num_fraction = 0; 670 | num_e = 0; 671 | 672 | if (b != '-') 673 | { 674 | flags |= flag_reproc; 675 | break; 676 | } 677 | 678 | flags |= flag_num_negative; 679 | continue; 680 | } 681 | else 682 | { sprintf (error, "%d:%d: Unexpected %c when seeking value", line_and_col, b); 683 | goto e_failed; 684 | } 685 | }; 686 | }; 687 | } 688 | else 689 | { 690 | switch (top->type) 691 | { 692 | case json_object: 693 | 694 | switch (b) 695 | { 696 | whitespace: 697 | continue; 698 | 699 | case '"': 700 | 701 | if (flags & flag_need_comma) 702 | { sprintf (error, "%d:%d: Expected , before \"", line_and_col); 703 | goto e_failed; 704 | } 705 | 706 | flags |= flag_string; 707 | 708 | string = (json_char *) top->_reserved.object_mem; 709 | string_length = 0; 710 | 711 | break; 712 | 713 | case '}': 714 | 715 | flags = (flags & ~ flag_need_comma) | flag_next; 716 | break; 717 | 718 | case ',': 719 | 720 | if (flags & flag_need_comma) 721 | { 722 | flags &= ~ flag_need_comma; 723 | break; 724 | } 725 | 726 | default: 727 | sprintf (error, "%d:%d: Unexpected `%c` in object", line_and_col, b); 728 | goto e_failed; 729 | }; 730 | 731 | break; 732 | 733 | case json_integer: 734 | case json_double: 735 | 736 | if (isdigit (b)) 737 | { 738 | ++ num_digits; 739 | 740 | if (top->type == json_integer || flags & flag_num_e) 741 | { 742 | if (! (flags & flag_num_e)) 743 | { 744 | if (flags & flag_num_zero) 745 | { sprintf (error, "%d:%d: Unexpected `0` before `%c`", line_and_col, b); 746 | goto e_failed; 747 | } 748 | 749 | if (num_digits == 1 && b == '0') 750 | flags |= flag_num_zero; 751 | } 752 | else 753 | { 754 | flags |= flag_num_e_got_sign; 755 | num_e = (num_e * 10) + (b - '0'); 756 | continue; 757 | } 758 | 759 | top->u.integer = (top->u.integer * 10) + (b - '0'); 760 | continue; 761 | } 762 | 763 | num_fraction = (num_fraction * 10) + (b - '0'); 764 | continue; 765 | } 766 | 767 | if (b == '+' || b == '-') 768 | { 769 | if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign)) 770 | { 771 | flags |= flag_num_e_got_sign; 772 | 773 | if (b == '-') 774 | flags |= flag_num_e_negative; 775 | 776 | continue; 777 | } 778 | } 779 | else if (b == '.' && top->type == json_integer) 780 | { 781 | if (!num_digits) 782 | { sprintf (error, "%d:%d: Expected digit before `.`", line_and_col); 783 | goto e_failed; 784 | } 785 | 786 | top->type = json_double; 787 | top->u.dbl = (double) top->u.integer; 788 | 789 | num_digits = 0; 790 | continue; 791 | } 792 | 793 | if (! (flags & flag_num_e)) 794 | { 795 | if (top->type == json_double) 796 | { 797 | if (!num_digits) 798 | { sprintf (error, "%d:%d: Expected digit after `.`", line_and_col); 799 | goto e_failed; 800 | } 801 | 802 | top->u.dbl += ((double) num_fraction) / (pow (10.0, (double) num_digits)); 803 | } 804 | 805 | if (b == 'e' || b == 'E') 806 | { 807 | flags |= flag_num_e; 808 | 809 | if (top->type == json_integer) 810 | { 811 | top->type = json_double; 812 | top->u.dbl = (double) top->u.integer; 813 | } 814 | 815 | num_digits = 0; 816 | flags &= ~ flag_num_zero; 817 | 818 | continue; 819 | } 820 | } 821 | else 822 | { 823 | if (!num_digits) 824 | { sprintf (error, "%d:%d: Expected digit after `e`", line_and_col); 825 | goto e_failed; 826 | } 827 | 828 | top->u.dbl *= pow (10.0, (double) 829 | (flags & flag_num_e_negative ? - num_e : num_e)); 830 | } 831 | 832 | if (flags & flag_num_negative) 833 | { 834 | if (top->type == json_integer) 835 | top->u.integer = - top->u.integer; 836 | else 837 | top->u.dbl = - top->u.dbl; 838 | } 839 | 840 | flags |= flag_next | flag_reproc; 841 | break; 842 | 843 | default: 844 | break; 845 | }; 846 | } 847 | 848 | if (flags & flag_reproc) 849 | { 850 | flags &= ~ flag_reproc; 851 | -- state.ptr; 852 | } 853 | 854 | if (flags & flag_next) 855 | { 856 | flags = (flags & ~ flag_next) | flag_need_comma; 857 | 858 | if (!top->parent) 859 | { 860 | /* root value done */ 861 | 862 | flags |= flag_done; 863 | continue; 864 | } 865 | 866 | if (top->parent->type == json_array) 867 | flags |= flag_seek_value; 868 | 869 | if (!state.first_pass) 870 | { 871 | json_value * parent = top->parent; 872 | 873 | switch (parent->type) 874 | { 875 | case json_object: 876 | 877 | parent->u.object.values 878 | [parent->u.object.length].value = top; 879 | 880 | break; 881 | 882 | case json_array: 883 | 884 | parent->u.array.values 885 | [parent->u.array.length] = top; 886 | 887 | break; 888 | 889 | default: 890 | break; 891 | }; 892 | } 893 | 894 | if ( (++ top->parent->u.array.length) > state.uint_max) 895 | goto e_overflow; 896 | 897 | top = top->parent; 898 | 899 | continue; 900 | } 901 | } 902 | 903 | alloc = root; 904 | } 905 | 906 | return root; 907 | 908 | e_unknown_value: 909 | 910 | sprintf (error, "%d:%d: Unknown value", line_and_col); 911 | goto e_failed; 912 | 913 | e_alloc_failure: 914 | 915 | strcpy (error, "Memory allocation failure"); 916 | goto e_failed; 917 | 918 | e_overflow: 919 | 920 | sprintf (error, "%d:%d: Too long (caught overflow)", line_and_col); 921 | goto e_failed; 922 | 923 | e_failed: 924 | 925 | if (error_buf) 926 | { 927 | if (*error) 928 | strcpy (error_buf, error); 929 | else 930 | strcpy (error_buf, "Unknown error"); 931 | } 932 | 933 | if (state.first_pass) 934 | alloc = root; 935 | 936 | while (alloc) 937 | { 938 | top = alloc->_reserved.next_alloc; 939 | state.settings.mem_free (alloc, state.settings.user_data); 940 | alloc = top; 941 | } 942 | 943 | if (!state.first_pass) 944 | json_value_free_ex (&state.settings, root); 945 | 946 | return 0; 947 | } 948 | 949 | json_value * json_parse (const json_char * json, size_t length) 950 | { 951 | json_settings settings = { 0 }; 952 | return json_parse_ex (&settings, json, length, 0); 953 | } 954 | 955 | void json_value_free_ex (json_settings * settings, json_value * value) 956 | { 957 | json_value * cur_value; 958 | 959 | if (!value) 960 | return; 961 | 962 | value->parent = 0; 963 | 964 | while (value) 965 | { 966 | switch (value->type) 967 | { 968 | case json_array: 969 | 970 | if (!value->u.array.length) 971 | { 972 | settings->mem_free (value->u.array.values, settings->user_data); 973 | break; 974 | } 975 | 976 | value = value->u.array.values [-- value->u.array.length]; 977 | continue; 978 | 979 | case json_object: 980 | 981 | if (!value->u.object.length) 982 | { 983 | settings->mem_free (value->u.object.values, settings->user_data); 984 | break; 985 | } 986 | 987 | value = value->u.object.values [-- value->u.object.length].value; 988 | continue; 989 | 990 | case json_string: 991 | 992 | settings->mem_free (value->u.string.ptr, settings->user_data); 993 | break; 994 | 995 | default: 996 | break; 997 | }; 998 | 999 | cur_value = value; 1000 | value = value->parent; 1001 | settings->mem_free (cur_value, settings->user_data); 1002 | } 1003 | } 1004 | 1005 | void json_value_free (json_value * value) 1006 | { 1007 | json_settings settings = { 0 }; 1008 | settings.mem_free = default_free; 1009 | json_value_free_ex (&settings, value); 1010 | } 1011 | 1012 | 1013 | -------------------------------------------------------------------------------- /dependencies/gen/json.h: -------------------------------------------------------------------------------- 1 | 2 | /* vim: set et ts=3 sw=3 sts=3 ft=c: 3 | * 4 | * Copyright (C) 2012, 2013, 2014 James McLaughlin et al. All rights reserved. 5 | * https://github.com/udp/json-parser 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _JSON_H 32 | #define _JSON_H 33 | 34 | #ifndef json_char 35 | #define json_char char 36 | #endif 37 | 38 | #ifndef json_int_t 39 | #ifndef _MSC_VER 40 | #include 41 | #define json_int_t int64_t 42 | #else 43 | #define json_int_t __int64 44 | #endif 45 | #endif 46 | 47 | #include 48 | 49 | #ifdef __cplusplus 50 | 51 | #include 52 | 53 | extern "C" 54 | { 55 | 56 | #endif 57 | 58 | typedef struct 59 | { 60 | unsigned long max_memory; 61 | int settings; 62 | 63 | /* Custom allocator support (leave null to use malloc/free) 64 | */ 65 | 66 | void * (* mem_alloc) (size_t, int zero, void * user_data); 67 | void (* mem_free) (void *, void * user_data); 68 | 69 | void * user_data; /* will be passed to mem_alloc and mem_free */ 70 | 71 | size_t value_extra; /* how much extra space to allocate for values? */ 72 | 73 | } json_settings; 74 | 75 | #define json_enable_comments 0x01 76 | 77 | typedef enum 78 | { 79 | json_none, 80 | json_object, 81 | json_array, 82 | json_integer, 83 | json_double, 84 | json_string, 85 | json_boolean, 86 | json_null 87 | 88 | } json_type; 89 | 90 | extern const struct _json_value json_value_none; 91 | 92 | typedef struct _json_object_entry 93 | { 94 | json_char * name; 95 | unsigned int name_length; 96 | 97 | struct _json_value * value; 98 | 99 | } json_object_entry; 100 | 101 | typedef struct _json_value 102 | { 103 | struct _json_value * parent; 104 | 105 | json_type type; 106 | 107 | union 108 | { 109 | int boolean; 110 | json_int_t integer; 111 | double dbl; 112 | 113 | struct 114 | { 115 | unsigned int length; 116 | json_char * ptr; /* null terminated */ 117 | 118 | } string; 119 | 120 | struct 121 | { 122 | unsigned int length; 123 | 124 | json_object_entry * values; 125 | 126 | #if defined(__cplusplus) && __cplusplus >= 201103L 127 | decltype(values) begin () const 128 | { return values; 129 | } 130 | decltype(values) end () const 131 | { return values + length; 132 | } 133 | #endif 134 | 135 | } object; 136 | 137 | struct 138 | { 139 | unsigned int length; 140 | struct _json_value ** values; 141 | 142 | #if defined(__cplusplus) && __cplusplus >= 201103L 143 | decltype(values) begin () const 144 | { return values; 145 | } 146 | decltype(values) end () const 147 | { return values + length; 148 | } 149 | #endif 150 | 151 | } array; 152 | 153 | } u; 154 | 155 | union 156 | { 157 | struct _json_value * next_alloc; 158 | void * object_mem; 159 | 160 | } _reserved; 161 | 162 | #ifdef JSON_TRACK_SOURCE 163 | 164 | /* Location of the value in the source JSON 165 | */ 166 | unsigned int line, col; 167 | 168 | #endif 169 | 170 | 171 | /* Some C++ operator sugar */ 172 | 173 | #ifdef __cplusplus 174 | 175 | public: 176 | 177 | inline _json_value () 178 | { memset (this, 0, sizeof (_json_value)); 179 | } 180 | 181 | inline const struct _json_value &operator [] (int index) const 182 | { 183 | if (type != json_array || index < 0 184 | || ((unsigned int) index) >= u.array.length) 185 | { 186 | return json_value_none; 187 | } 188 | 189 | return *u.array.values [index]; 190 | } 191 | 192 | inline const struct _json_value &operator [] (const char * index) const 193 | { 194 | if (type != json_object) 195 | return json_value_none; 196 | 197 | for (unsigned int i = 0; i < u.object.length; ++ i) 198 | if (!strcmp (u.object.values [i].name, index)) 199 | return *u.object.values [i].value; 200 | 201 | return json_value_none; 202 | } 203 | 204 | inline operator const char * () const 205 | { 206 | switch (type) 207 | { 208 | case json_string: 209 | return u.string.ptr; 210 | 211 | default: 212 | return ""; 213 | }; 214 | } 215 | 216 | inline operator json_int_t () const 217 | { 218 | switch (type) 219 | { 220 | case json_integer: 221 | return u.integer; 222 | 223 | case json_double: 224 | return (json_int_t) u.dbl; 225 | 226 | default: 227 | return 0; 228 | }; 229 | } 230 | 231 | inline operator bool () const 232 | { 233 | if (type != json_boolean) 234 | return false; 235 | 236 | return u.boolean != 0; 237 | } 238 | 239 | inline operator double () const 240 | { 241 | switch (type) 242 | { 243 | case json_integer: 244 | return (double) u.integer; 245 | 246 | case json_double: 247 | return u.dbl; 248 | 249 | default: 250 | return 0; 251 | }; 252 | } 253 | 254 | #endif 255 | 256 | } json_value; 257 | 258 | json_value * json_parse (const json_char * json, 259 | size_t length); 260 | 261 | #define json_error_max 128 262 | json_value * json_parse_ex (json_settings * settings, 263 | const json_char * json, 264 | size_t length, 265 | char * error); 266 | 267 | void json_value_free (json_value *); 268 | 269 | 270 | /* Not usually necessary, unless you used a custom mem_alloc and now want to 271 | * use a custom mem_free. 272 | */ 273 | void json_value_free_ex (json_settings * settings, 274 | json_value *); 275 | 276 | 277 | #ifdef __cplusplus 278 | } /* extern "C" */ 279 | #endif 280 | 281 | #endif 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /dependencies/gen/json_builder.c: -------------------------------------------------------------------------------- 1 | 2 | /* vim: set et ts=3 sw=3 sts=3 ft=c: 3 | * 4 | * Copyright (C) 2014 James McLaughlin. All rights reserved. 5 | * https://github.com/udp/json-builder 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #include "json_builder.h" 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifdef _MSC_VER 39 | #define snprintf _snprintf 40 | #endif 41 | 42 | const static json_serialize_opts default_opts = 43 | { 44 | json_serialize_mode_single_line, 45 | 0, 46 | 3 /* indent_size */ 47 | }; 48 | 49 | typedef struct json_builder_value 50 | { 51 | json_value value; 52 | 53 | int is_builder_value; 54 | 55 | size_t additional_length_allocated; 56 | size_t length_iterated; 57 | 58 | } json_builder_value; 59 | 60 | static int builderize (json_value * value) 61 | { 62 | if (((json_builder_value *) value)->is_builder_value) 63 | return 1; 64 | 65 | if (value->type == json_object) 66 | { 67 | unsigned int i; 68 | 69 | /* Values straight out of the parser have the names of object entries 70 | * allocated in the same allocation as the values array itself. This is 71 | * not desirable when manipulating values because the names would be easy 72 | * to clobber. 73 | */ 74 | for (i = 0; i < value->u.object.length; ++ i) 75 | { 76 | json_char * name_copy; 77 | json_object_entry * entry = &value->u.object.values [i]; 78 | 79 | if (! (name_copy = (json_char *) malloc ((entry->name_length + 1) * sizeof (json_char)))) 80 | return 0; 81 | 82 | memcpy (name_copy, entry->name, entry->name_length + 1); 83 | entry->name = name_copy; 84 | } 85 | } 86 | 87 | ((json_builder_value *) value)->is_builder_value = 1; 88 | 89 | return 1; 90 | } 91 | 92 | const size_t json_builder_extra = sizeof(json_builder_value) - sizeof(json_value); 93 | 94 | /* These flags are set up from the opts before serializing to make the 95 | * serializer conditions simpler. 96 | */ 97 | const int f_spaces_around_brackets = (1 << 0); 98 | const int f_spaces_after_commas = (1 << 1); 99 | const int f_spaces_after_colons = (1 << 2); 100 | const int f_tabs = (1 << 3); 101 | 102 | int get_serialize_flags (json_serialize_opts opts) 103 | { 104 | int flags = 0; 105 | 106 | if (opts.mode == json_serialize_mode_packed) 107 | return 0; 108 | 109 | if (opts.mode == json_serialize_mode_multiline) 110 | { 111 | if (opts.opts & json_serialize_opt_use_tabs) 112 | flags |= f_tabs; 113 | } 114 | else 115 | { 116 | if (! (opts.opts & json_serialize_opt_pack_brackets)) 117 | flags |= f_spaces_around_brackets; 118 | 119 | if (! (opts.opts & json_serialize_opt_no_space_after_comma)) 120 | flags |= f_spaces_after_commas; 121 | } 122 | 123 | if (! (opts.opts & json_serialize_opt_no_space_after_colon)) 124 | flags |= f_spaces_after_colons; 125 | 126 | return flags; 127 | } 128 | 129 | json_value * json_array_new (size_t length) 130 | { 131 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 132 | 133 | if (!value) 134 | return NULL; 135 | 136 | ((json_builder_value *) value)->is_builder_value = 1; 137 | 138 | value->type = json_array; 139 | 140 | if (! (value->u.array.values = (json_value **) malloc (length * sizeof (json_value *)))) 141 | { 142 | free (value); 143 | return NULL; 144 | } 145 | 146 | ((json_builder_value *) value)->additional_length_allocated = length; 147 | 148 | return value; 149 | } 150 | 151 | json_value * json_array_push (json_value * array, json_value * value) 152 | { 153 | assert (array->type == json_array); 154 | 155 | if (!builderize (array) || !builderize (value)) 156 | return NULL; 157 | 158 | if (((json_builder_value *) array)->additional_length_allocated > 0) 159 | { 160 | -- ((json_builder_value *) array)->additional_length_allocated; 161 | } 162 | else 163 | { 164 | json_value ** values_new = (json_value **) realloc 165 | (array->u.array.values, sizeof (json_value *) * (array->u.array.length + 1)); 166 | 167 | if (!values_new) 168 | return NULL; 169 | 170 | array->u.array.values = values_new; 171 | } 172 | 173 | array->u.array.values [array->u.array.length] = value; 174 | ++ array->u.array.length; 175 | 176 | value->parent = array; 177 | 178 | return value; 179 | } 180 | 181 | json_value * json_object_new (size_t length) 182 | { 183 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 184 | 185 | if (!value) 186 | return NULL; 187 | 188 | ((json_builder_value *) value)->is_builder_value = 1; 189 | 190 | value->type = json_object; 191 | 192 | if (! (value->u.object.values = (json_object_entry *) calloc 193 | (length, sizeof (*value->u.object.values)))) 194 | { 195 | free (value); 196 | return NULL; 197 | } 198 | 199 | ((json_builder_value *) value)->additional_length_allocated = length; 200 | 201 | return value; 202 | } 203 | 204 | json_value * json_object_push (json_value * object, 205 | const json_char * name, 206 | json_value * value) 207 | { 208 | return json_object_push_length (object, strlen (name), name, value); 209 | } 210 | 211 | json_value * json_object_push_length (json_value * object, 212 | unsigned int name_length, const json_char * name, 213 | json_value * value) 214 | { 215 | json_char * name_copy; 216 | 217 | assert (object->type == json_object); 218 | 219 | if (! (name_copy = (json_char *) malloc ((name_length + 1) * sizeof (json_char)))) 220 | return NULL; 221 | 222 | memcpy (name_copy, name, name_length * sizeof (json_char)); 223 | name_copy [name_length] = 0; 224 | 225 | if (!json_object_push_nocopy (object, name_length, name_copy, value)) 226 | { 227 | free (name_copy); 228 | return NULL; 229 | } 230 | 231 | return value; 232 | } 233 | 234 | json_value * json_object_push_nocopy (json_value * object, 235 | unsigned int name_length, json_char * name, 236 | json_value * value) 237 | { 238 | json_object_entry * entry; 239 | 240 | assert (object->type == json_object); 241 | 242 | if (!builderize (object) || !builderize (value)) 243 | return NULL; 244 | 245 | if (((json_builder_value *) object)->additional_length_allocated > 0) 246 | { 247 | -- ((json_builder_value *) object)->additional_length_allocated; 248 | } 249 | else 250 | { 251 | json_object_entry * values_new = (json_object_entry *) 252 | realloc (object->u.object.values, sizeof (*object->u.object.values) 253 | * (object->u.object.length + 1)); 254 | 255 | if (!values_new) 256 | return NULL; 257 | 258 | object->u.object.values = values_new; 259 | } 260 | 261 | entry = object->u.object.values + object->u.object.length; 262 | 263 | entry->name_length = name_length; 264 | entry->name = name; 265 | entry->value = value; 266 | 267 | ++ object->u.object.length; 268 | 269 | value->parent = object; 270 | 271 | return value; 272 | } 273 | 274 | json_value * json_string_new (const json_char * buf) 275 | { 276 | return json_string_new_length (strlen (buf), buf); 277 | } 278 | 279 | json_value * json_string_new_length (unsigned int length, const json_char * buf) 280 | { 281 | json_value * value; 282 | json_char * copy = (json_char *) malloc ((length + 1) * sizeof (json_char)); 283 | 284 | if (!copy) 285 | return NULL; 286 | 287 | memcpy (copy, buf, length * sizeof (json_char)); 288 | copy [length] = 0; 289 | 290 | if (! (value = json_string_new_nocopy (length, copy))) 291 | { 292 | free (copy); 293 | return NULL; 294 | } 295 | 296 | return value; 297 | } 298 | 299 | json_value * json_string_new_nocopy (unsigned int length, json_char * buf) 300 | { 301 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 302 | 303 | if (!value) 304 | return NULL; 305 | 306 | ((json_builder_value *) value)->is_builder_value = 1; 307 | 308 | value->type = json_string; 309 | value->u.string.length = length; 310 | value->u.string.ptr = buf; 311 | 312 | return value; 313 | } 314 | 315 | json_value * json_integer_new (json_int_t integer) 316 | { 317 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 318 | 319 | if (!value) 320 | return NULL; 321 | 322 | ((json_builder_value *) value)->is_builder_value = 1; 323 | 324 | value->type = json_integer; 325 | value->u.integer = integer; 326 | 327 | return value; 328 | } 329 | 330 | json_value * json_double_new (double dbl) 331 | { 332 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 333 | 334 | if (!value) 335 | return NULL; 336 | 337 | ((json_builder_value *) value)->is_builder_value = 1; 338 | 339 | value->type = json_double; 340 | value->u.dbl = dbl; 341 | 342 | return value; 343 | } 344 | 345 | json_value * json_boolean_new (int b) 346 | { 347 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 348 | 349 | if (!value) 350 | return NULL; 351 | 352 | ((json_builder_value *) value)->is_builder_value = 1; 353 | 354 | value->type = json_boolean; 355 | value->u.boolean = b; 356 | 357 | return value; 358 | } 359 | 360 | json_value * json_null_new () 361 | { 362 | json_value * value = (json_value *) calloc (1, sizeof (json_builder_value)); 363 | 364 | if (!value) 365 | return NULL; 366 | 367 | ((json_builder_value *) value)->is_builder_value = 1; 368 | 369 | value->type = json_null; 370 | 371 | return value; 372 | } 373 | 374 | void json_object_sort (json_value * object, json_value * proto) 375 | { 376 | unsigned int i, out_index = 0; 377 | 378 | if (!builderize (object)) 379 | return; /* TODO error */ 380 | 381 | assert (object->type == json_object); 382 | assert (proto->type == json_object); 383 | 384 | for (i = 0; i < proto->u.object.length; ++ i) 385 | { 386 | unsigned int j; 387 | json_object_entry proto_entry = proto->u.object.values [i]; 388 | 389 | for (j = 0; j < object->u.object.length; ++ j) 390 | { 391 | json_object_entry entry = object->u.object.values [j]; 392 | 393 | if (entry.name_length != proto_entry.name_length) 394 | continue; 395 | 396 | if (memcmp (entry.name, proto_entry.name, entry.name_length) != 0) 397 | continue; 398 | 399 | object->u.object.values [j] = object->u.object.values [out_index]; 400 | object->u.object.values [out_index] = entry; 401 | 402 | ++ out_index; 403 | } 404 | } 405 | } 406 | 407 | json_value * json_object_merge (json_value * objectA, json_value * objectB) 408 | { 409 | unsigned int i; 410 | 411 | assert (objectA->type == json_object); 412 | assert (objectB->type == json_object); 413 | assert (objectA != objectB); 414 | 415 | if (!builderize (objectA) || !builderize (objectB)) 416 | return NULL; 417 | 418 | if (objectB->u.object.length <= 419 | ((json_builder_value *) objectA)->additional_length_allocated) 420 | { 421 | ((json_builder_value *) objectA)->additional_length_allocated 422 | -= objectB->u.object.length; 423 | } 424 | else 425 | { 426 | json_object_entry * values_new; 427 | 428 | unsigned int alloc = 429 | objectA->u.object.length 430 | + ((json_builder_value *) objectA)->additional_length_allocated 431 | + objectB->u.object.length; 432 | 433 | if (! (values_new = (json_object_entry *) 434 | realloc (objectA->u.object.values, sizeof (json_object_entry) * alloc))) 435 | { 436 | return NULL; 437 | } 438 | 439 | objectA->u.object.values = values_new; 440 | } 441 | 442 | for (i = 0; i < objectB->u.object.length; ++ i) 443 | { 444 | json_object_entry * entry = &objectA->u.object.values[objectA->u.object.length + i]; 445 | 446 | *entry = objectB->u.object.values[i]; 447 | entry->value->parent = objectA; 448 | } 449 | 450 | objectA->u.object.length += objectB->u.object.length; 451 | 452 | free (objectB->u.object.values); 453 | free (objectB); 454 | 455 | return objectA; 456 | } 457 | 458 | static size_t measure_string (unsigned int length, 459 | const json_char * str) 460 | { 461 | unsigned int i; 462 | size_t measured_length = 0; 463 | 464 | for(i = 0; i < length; ++ i) 465 | { 466 | json_char c = str [i]; 467 | 468 | switch (c) 469 | { 470 | case '"': 471 | case '\\': 472 | case '/': 473 | case '\b': 474 | case '\f': 475 | case '\n': 476 | case '\r': 477 | case '\t': 478 | 479 | measured_length += 2; 480 | break; 481 | 482 | default: 483 | 484 | ++ measured_length; 485 | break; 486 | }; 487 | }; 488 | 489 | return measured_length; 490 | } 491 | 492 | #define PRINT_ESCAPED(c) do { \ 493 | *buf ++ = '\\'; \ 494 | *buf ++ = (c); \ 495 | } while(0); \ 496 | 497 | static size_t serialize_string (json_char * buf, 498 | unsigned int length, 499 | const json_char * str) 500 | { 501 | json_char * orig_buf = buf; 502 | unsigned int i; 503 | 504 | for(i = 0; i < length; ++ i) 505 | { 506 | json_char c = str [i]; 507 | 508 | switch (c) 509 | { 510 | case '"': PRINT_ESCAPED ('\"'); continue; 511 | case '\\': PRINT_ESCAPED ('\\'); continue; 512 | case '/': PRINT_ESCAPED ('/'); continue; 513 | case '\b': PRINT_ESCAPED ('b'); continue; 514 | case '\f': PRINT_ESCAPED ('f'); continue; 515 | case '\n': PRINT_ESCAPED ('n'); continue; 516 | case '\r': PRINT_ESCAPED ('r'); continue; 517 | case '\t': PRINT_ESCAPED ('t'); continue; 518 | 519 | default: 520 | 521 | *buf ++ = c; 522 | break; 523 | }; 524 | }; 525 | 526 | return buf - orig_buf; 527 | } 528 | 529 | size_t json_measure (json_value * value) 530 | { 531 | return json_measure_ex (value, default_opts); 532 | } 533 | 534 | #define MEASURE_NEWLINE() do { \ 535 | ++ newlines; \ 536 | indents += depth; \ 537 | } while(0); \ 538 | 539 | size_t json_measure_ex (json_value * value, json_serialize_opts opts) 540 | { 541 | size_t total = 1; /* null terminator */ 542 | size_t newlines = 0; 543 | size_t depth = 0; 544 | size_t indents = 0; 545 | int flags; 546 | int bracket_size, comma_size, colon_size; 547 | 548 | flags = get_serialize_flags (opts); 549 | 550 | /* to reduce branching 551 | */ 552 | bracket_size = flags & f_spaces_around_brackets ? 2 : 1; 553 | comma_size = flags & f_spaces_after_commas ? 2 : 1; 554 | colon_size = flags & f_spaces_after_colons ? 2 : 1; 555 | 556 | while (value) 557 | { 558 | json_int_t integer; 559 | json_object_entry * entry; 560 | 561 | switch (value->type) 562 | { 563 | case json_array: 564 | 565 | if (((json_builder_value *) value)->length_iterated == 0) 566 | { 567 | if (value->u.array.length == 0) 568 | { 569 | total += 2; /* `[]` */ 570 | break; 571 | } 572 | 573 | total += bracket_size; /* `[` */ 574 | 575 | ++ depth; 576 | MEASURE_NEWLINE(); /* \n after [ */ 577 | } 578 | 579 | if (((json_builder_value *) value)->length_iterated == value->u.array.length) 580 | { 581 | -- depth; 582 | MEASURE_NEWLINE(); 583 | total += bracket_size; /* `]` */ 584 | 585 | ((json_builder_value *) value)->length_iterated = 0; 586 | break; 587 | } 588 | 589 | if (((json_builder_value *) value)->length_iterated > 0) 590 | { 591 | total += comma_size; /* `, ` */ 592 | 593 | MEASURE_NEWLINE(); 594 | } 595 | 596 | ((json_builder_value *) value)->length_iterated++; 597 | value = value->u.array.values [((json_builder_value *) value)->length_iterated - 1]; 598 | continue; 599 | 600 | case json_object: 601 | 602 | if (((json_builder_value *) value)->length_iterated == 0) 603 | { 604 | if (value->u.object.length == 0) 605 | { 606 | total += 2; /* `{}` */ 607 | break; 608 | } 609 | 610 | total += bracket_size; /* `{` */ 611 | 612 | ++ depth; 613 | MEASURE_NEWLINE(); /* \n after { */ 614 | } 615 | 616 | if (((json_builder_value *) value)->length_iterated == value->u.object.length) 617 | { 618 | -- depth; 619 | MEASURE_NEWLINE(); 620 | total += bracket_size; /* `}` */ 621 | 622 | ((json_builder_value *) value)->length_iterated = 0; 623 | break; 624 | } 625 | 626 | if (((json_builder_value *) value)->length_iterated > 0) 627 | { 628 | total += comma_size; /* `, ` */ 629 | MEASURE_NEWLINE(); 630 | } 631 | 632 | entry = value->u.object.values + (((json_builder_value *) value)->length_iterated ++); 633 | 634 | total += 2 + colon_size; /* `"": ` */ 635 | total += measure_string (entry->name_length, entry->name); 636 | 637 | value = entry->value; 638 | continue; 639 | 640 | case json_string: 641 | 642 | total += 2; /* `""` */ 643 | total += measure_string (value->u.string.length, value->u.string.ptr); 644 | break; 645 | 646 | case json_integer: 647 | 648 | integer = value->u.integer; 649 | 650 | if (integer < 0) 651 | { 652 | total += 1; /* `-` */ 653 | integer = - integer; 654 | } 655 | 656 | ++ total; /* first digit */ 657 | 658 | while (integer >= 10) 659 | { 660 | ++ total; /* another digit */ 661 | integer /= 10; 662 | } 663 | 664 | break; 665 | 666 | case json_double: 667 | 668 | total += snprintf (NULL, 0, "%g", value->u.dbl); 669 | 670 | if (value->u.dbl - floor (value->u.dbl) < 0.001) 671 | total += 2; 672 | 673 | break; 674 | 675 | case json_boolean: 676 | 677 | total += value->u.boolean ? 678 | 4: /* `true` */ 679 | 5; /* `false` */ 680 | 681 | break; 682 | 683 | case json_null: 684 | 685 | total += 4; /* `null` */ 686 | break; 687 | 688 | default: 689 | break; 690 | }; 691 | 692 | value = value->parent; 693 | } 694 | 695 | if (opts.mode == json_serialize_mode_multiline) 696 | { 697 | total += newlines * (((opts.opts & json_serialize_opt_CRLF) ? 2 : 1) + opts.indent_size); 698 | total += indents * opts.indent_size; 699 | } 700 | 701 | return total; 702 | } 703 | 704 | void json_serialize (json_char * buf, json_value * value) 705 | { 706 | json_serialize_ex (buf, value, default_opts); 707 | } 708 | 709 | #define PRINT_NEWLINE() do { \ 710 | if (opts.mode == json_serialize_mode_multiline) { \ 711 | if (opts.opts & json_serialize_opt_CRLF) \ 712 | *buf ++ = '\r'; \ 713 | *buf ++ = '\n'; \ 714 | for(i = 0; i < indent; ++ i) \ 715 | *buf ++ = indent_char; \ 716 | } \ 717 | } while(0); \ 718 | 719 | #define PRINT_OPENING_BRACKET(c) do { \ 720 | *buf ++ = (c); \ 721 | if (flags & f_spaces_around_brackets) \ 722 | *buf ++ = ' '; \ 723 | } while(0); \ 724 | 725 | #define PRINT_CLOSING_BRACKET(c) do { \ 726 | if (flags & f_spaces_around_brackets) \ 727 | *buf ++ = ' '; \ 728 | *buf ++ = (c); \ 729 | } while(0); \ 730 | 731 | void json_serialize_ex (json_char * buf, json_value * value, json_serialize_opts opts) 732 | { 733 | json_int_t integer, orig_integer; 734 | json_object_entry * entry; 735 | json_char * ptr, * dot; 736 | int indent = 0; 737 | char indent_char; 738 | int i; 739 | int flags; 740 | 741 | flags = get_serialize_flags (opts); 742 | 743 | indent_char = flags & f_tabs ? '\t' : ' '; 744 | 745 | while (value) 746 | { 747 | switch (value->type) 748 | { 749 | case json_array: 750 | 751 | if (((json_builder_value *) value)->length_iterated == 0) 752 | { 753 | if (value->u.array.length == 0) 754 | { 755 | *buf ++ = '['; 756 | *buf ++ = ']'; 757 | 758 | break; 759 | } 760 | 761 | PRINT_OPENING_BRACKET ('['); 762 | 763 | indent += opts.indent_size; 764 | PRINT_NEWLINE(); 765 | } 766 | 767 | if (((json_builder_value *) value)->length_iterated == value->u.array.length) 768 | { 769 | indent -= opts.indent_size; 770 | PRINT_NEWLINE(); 771 | PRINT_CLOSING_BRACKET (']'); 772 | 773 | ((json_builder_value *) value)->length_iterated = 0; 774 | break; 775 | } 776 | 777 | if (((json_builder_value *) value)->length_iterated > 0) 778 | { 779 | *buf ++ = ','; 780 | 781 | if (flags & f_spaces_after_commas) 782 | *buf ++ = ' '; 783 | 784 | PRINT_NEWLINE(); 785 | } 786 | 787 | ((json_builder_value *) value)->length_iterated++; 788 | value = value->u.array.values [((json_builder_value *) value)->length_iterated - 1]; 789 | continue; 790 | 791 | case json_object: 792 | 793 | if (((json_builder_value *) value)->length_iterated == 0) 794 | { 795 | if (value->u.object.length == 0) 796 | { 797 | *buf ++ = '{'; 798 | *buf ++ = '}'; 799 | 800 | break; 801 | } 802 | 803 | PRINT_OPENING_BRACKET ('{'); 804 | 805 | indent += opts.indent_size; 806 | PRINT_NEWLINE(); 807 | } 808 | 809 | if (((json_builder_value *) value)->length_iterated == value->u.object.length) 810 | { 811 | indent -= opts.indent_size; 812 | PRINT_NEWLINE(); 813 | PRINT_CLOSING_BRACKET ('}'); 814 | 815 | ((json_builder_value *) value)->length_iterated = 0; 816 | break; 817 | } 818 | 819 | if (((json_builder_value *) value)->length_iterated > 0) 820 | { 821 | *buf ++ = ','; 822 | 823 | if (flags & f_spaces_after_commas) 824 | *buf ++ = ' '; 825 | 826 | PRINT_NEWLINE(); 827 | } 828 | 829 | entry = value->u.object.values + (((json_builder_value *) value)->length_iterated ++); 830 | 831 | *buf ++ = '\"'; 832 | buf += serialize_string (buf, entry->name_length, entry->name); 833 | *buf ++ = '\"'; 834 | *buf ++ = ':'; 835 | 836 | if (flags & f_spaces_after_colons) 837 | *buf ++ = ' '; 838 | 839 | value = entry->value; 840 | continue; 841 | 842 | case json_string: 843 | 844 | *buf ++ = '\"'; 845 | buf += serialize_string (buf, value->u.string.length, value->u.string.ptr); 846 | *buf ++ = '\"'; 847 | break; 848 | 849 | case json_integer: 850 | 851 | integer = value->u.integer; 852 | 853 | if (integer < 0) 854 | { 855 | *buf ++ = '-'; 856 | integer = - integer; 857 | } 858 | 859 | orig_integer = integer; 860 | 861 | ++ buf; 862 | 863 | while (integer >= 10) 864 | { 865 | ++ buf; 866 | integer /= 10; 867 | } 868 | 869 | integer = orig_integer; 870 | ptr = buf; 871 | 872 | do 873 | { 874 | *-- ptr = "0123456789"[integer % 10]; 875 | 876 | } while ((integer /= 10) > 0); 877 | 878 | break; 879 | 880 | case json_double: 881 | 882 | ptr = buf; 883 | 884 | buf += sprintf (buf, "%g", value->u.dbl); 885 | 886 | if ((dot = strchr (ptr, ','))) 887 | { 888 | *dot = '.'; 889 | } 890 | else if (!strchr (ptr, '.')) 891 | { 892 | *buf ++ = '.'; 893 | *buf ++ = '0'; 894 | } 895 | 896 | break; 897 | 898 | case json_boolean: 899 | 900 | if (value->u.boolean) 901 | { 902 | memcpy (buf, "true", 4); 903 | buf += 4; 904 | } 905 | else 906 | { 907 | memcpy (buf, "false", 5); 908 | buf += 5; 909 | } 910 | 911 | break; 912 | 913 | case json_null: 914 | 915 | memcpy (buf, "null", 4); 916 | buf += 4; 917 | break; 918 | 919 | default: 920 | break; 921 | }; 922 | 923 | value = value->parent; 924 | } 925 | 926 | *buf = 0; 927 | } 928 | 929 | void json_builder_free (json_value * value) 930 | { 931 | json_value * cur_value; 932 | 933 | if (!value) 934 | return; 935 | 936 | value->parent = 0; 937 | 938 | while (value) 939 | { 940 | switch (value->type) 941 | { 942 | case json_array: 943 | 944 | if (!value->u.array.length) 945 | { 946 | free (value->u.array.values); 947 | break; 948 | } 949 | 950 | value = value->u.array.values [-- value->u.array.length]; 951 | continue; 952 | 953 | case json_object: 954 | 955 | if (!value->u.object.length) 956 | { 957 | free (value->u.object.values); 958 | break; 959 | } 960 | 961 | -- value->u.object.length; 962 | 963 | if (((json_builder_value *) value)->is_builder_value) 964 | { 965 | /* Names are allocated separately for builder values. In parser 966 | * values, they are part of the same allocation as the values array 967 | * itself. 968 | */ 969 | free (value->u.object.values [value->u.object.length].name); 970 | } 971 | 972 | value = value->u.object.values [value->u.object.length].value; 973 | continue; 974 | 975 | case json_string: 976 | 977 | free (value->u.string.ptr); 978 | break; 979 | 980 | default: 981 | break; 982 | }; 983 | 984 | cur_value = value; 985 | value = value->parent; 986 | free (cur_value); 987 | } 988 | } 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | -------------------------------------------------------------------------------- /dependencies/gen/json_builder.h: -------------------------------------------------------------------------------- 1 | 2 | /* vim: set et ts=3 sw=3 sts=3 ft=c: 3 | * 4 | * Copyright (C) 2014 James McLaughlin. All rights reserved. 5 | * https://github.com/udp/json-builder 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions 9 | * are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright 12 | * notice, this list of conditions and the following disclaimer. 13 | * 14 | * 2. Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 | * SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _JSON_BUILDER_H 32 | #define _JSON_BUILDER_H 33 | 34 | /* Requires json.h from json-parser 35 | * https://github.com/udp/json-parser 36 | */ 37 | #include "json.h" 38 | 39 | #ifdef __cplusplus 40 | extern "C" 41 | { 42 | #endif 43 | 44 | /* IMPORTANT NOTE: If you want to use json-builder functions with values 45 | * allocated by json-parser as part of the parsing process, you must pass 46 | * json_builder_extra as the value_extra setting in json_settings when 47 | * parsing. Otherwise there will not be room for the extra state and 48 | * json-builder WILL invoke undefined behaviour. 49 | * 50 | * Also note that unlike json-parser, json-builder does not currently support 51 | * custom allocators (for no particular reason other than that it doesn't have 52 | * any settings or global state.) 53 | */ 54 | extern const size_t json_builder_extra; 55 | 56 | 57 | /*** Arrays 58 | *** 59 | * Note that all of these length arguments are just a hint to allow for 60 | * pre-allocation - passing 0 is fine. 61 | */ 62 | json_value * json_array_new (size_t length); 63 | json_value * json_array_push (json_value * array, json_value *); 64 | 65 | 66 | /*** Objects 67 | ***/ 68 | json_value * json_object_new (size_t length); 69 | 70 | json_value * json_object_push (json_value * object, 71 | const json_char * name, 72 | json_value *); 73 | 74 | /* Same as json_object_push, but doesn't call strlen() for you. 75 | */ 76 | json_value * json_object_push_length (json_value * object, 77 | unsigned int name_length, const json_char * name, 78 | json_value *); 79 | 80 | /* Same as json_object_push_length, but doesn't copy the name buffer before 81 | * storing it in the value. Use this micro-optimisation at your own risk. 82 | */ 83 | json_value * json_object_push_nocopy (json_value * object, 84 | unsigned int name_length, json_char * name, 85 | json_value *); 86 | 87 | /* Merges all entries from objectB into objectA and destroys objectB. 88 | */ 89 | json_value * json_object_merge (json_value * objectA, json_value * objectB); 90 | 91 | /* Sort the entries of an object based on the order in a prototype object. 92 | * Helpful when reading JSON and writing it again to preserve user order. 93 | */ 94 | void json_object_sort (json_value * object, json_value * proto); 95 | 96 | 97 | 98 | /*** Strings 99 | ***/ 100 | json_value * json_string_new (const json_char *); 101 | json_value * json_string_new_length (unsigned int length, const json_char *); 102 | json_value * json_string_new_nocopy (unsigned int length, json_char *); 103 | 104 | 105 | /*** Everything else 106 | ***/ 107 | json_value * json_integer_new (json_int_t); 108 | json_value * json_double_new (double); 109 | json_value * json_boolean_new (int); 110 | json_value * json_null_new (); 111 | 112 | 113 | /*** Serializing 114 | ***/ 115 | #define json_serialize_mode_multiline 0 116 | #define json_serialize_mode_single_line 1 117 | #define json_serialize_mode_packed 2 118 | 119 | #define json_serialize_opt_CRLF (1 << 1) 120 | #define json_serialize_opt_pack_brackets (1 << 2) 121 | #define json_serialize_opt_no_space_after_comma (1 << 3) 122 | #define json_serialize_opt_no_space_after_colon (1 << 4) 123 | #define json_serialize_opt_use_tabs (1 << 5) 124 | 125 | typedef struct json_serialize_opts 126 | { 127 | int mode; 128 | int opts; 129 | int indent_size; 130 | 131 | } json_serialize_opts; 132 | 133 | 134 | /* Returns a length in characters that is at least large enough to hold the 135 | * value in its serialized form, including a null terminator. 136 | */ 137 | size_t json_measure (json_value *); 138 | size_t json_measure_ex (json_value *, json_serialize_opts); 139 | 140 | 141 | /* Serializes a JSON value into the buffer given (which must already be 142 | * allocated with a length of at least json_measure(value, opts)) 143 | */ 144 | void json_serialize (json_char * buf, json_value *); 145 | void json_serialize_ex (json_char * buf, json_value *, json_serialize_opts); 146 | 147 | 148 | /*** Cleaning up 149 | ***/ 150 | void json_builder_free (json_value *); 151 | 152 | #ifdef __cplusplus 153 | } 154 | #endif 155 | 156 | #endif 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /include/AudioMidiHost.h: -------------------------------------------------------------------------------- 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 | #ifndef _AudioMidiHost_h_ 25 | #define _AudioMidiHost_h_ 26 | 27 | // pure virtual base class for audio/midi backends (portaudio, rtaudio, etc.) 28 | 29 | #include 30 | #include 31 | 32 | namespace GenPi { 33 | 34 | class AudioMidiHost { 35 | 36 | public: 37 | 38 | virtual ~AudioMidiHost() {} 39 | 40 | virtual int setup() = 0; 41 | virtual int run() = 0; 42 | virtual void shutdown() = 0; 43 | virtual int restart() = 0; 44 | 45 | virtual std::vector getAudioInDevices() const = 0; 46 | virtual int setAudioInDevice(int device) = 0; 47 | 48 | virtual std::vector getAudioOutDevices() const = 0; 49 | virtual int setAudioOutDevice(int device) = 0; 50 | 51 | virtual std::vector getMidiInPorts() const = 0; 52 | virtual int setMidiInPort(int port) = 0; 53 | 54 | virtual std::vector getMidiOutPorts() const = 0; 55 | virtual int setMidiOutPort(int port) = 0; 56 | 57 | virtual std::string getName() const = 0; 58 | 59 | }; 60 | 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/GenPi.h: -------------------------------------------------------------------------------- 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 | #ifndef _GenPi_h_ 25 | #define _GenPi_h_ 26 | 27 | #include 28 | #include "gen_exported.h" 29 | #include "Host.h" 30 | #include "Settings.h" 31 | #include "Globals.h" 32 | #include "HardwareEncoder.h" 33 | #include 34 | 35 | namespace GenPi { 36 | 37 | static std::string getWorkingPath(int argc, const char* argv[]); 38 | 39 | template 40 | class Runner { 41 | static_assert(std::is_base_of::value, "Runner template parameter must derive from AudioMidiHost"); 42 | 43 | public: 44 | 45 | Runner(int argc, const char* argv[]) 46 | : m_encoder(nullptr) { 47 | m_workingPath = getWorkingPath(argc, argv); 48 | m_encoder = getHardware(); 49 | } 50 | 51 | ~Runner() { 52 | if (m_encoder) { 53 | delete m_encoder; 54 | } 55 | } 56 | 57 | int setup() { 58 | setupSettings(); 59 | return m_host.setup(); 60 | } 61 | 62 | int run() { 63 | return m_host.run(); 64 | } 65 | 66 | void shutdown() { 67 | shutdownSettings(); 68 | return m_host.shutdown(); 69 | } 70 | 71 | int configure() { // TODO Configuration could be its own class, I suppose 72 | int rv = 0; 73 | 74 | std::cout << "\nSelect from the following choices:\n" 75 | << "[0] Modify Parameter\n" 76 | << "[1] Configure Audio Input\n" 77 | << "[2] Configure Audio Output\n" 78 | /* 79 | << "[3] Configure Midi Input\n" 80 | << "[4] Configure Midi Output\n" 81 | */ 82 | << "[q] Quit" << std::endl; 83 | 84 | std::cout << "\n[0 - 2, q]: "; 85 | int config = getchar(); 86 | 87 | switch(config) { 88 | case '0': modifyParameter(); break; 89 | case '1': configureAudioInput(); break; 90 | case '2': configureAudioOutput(); break; 91 | /* 92 | case '3': configureMidiInput(); break; 93 | case '4': configureMidiOutput(); break; 94 | */ 95 | case 'q': shutdown(); rv = 1; break; 96 | case -1: rv = -1; break; 97 | default: break; 98 | } 99 | std::cout << std::endl; 100 | return rv; 101 | } 102 | 103 | private: 104 | 105 | int getchar() { 106 | std::string line; 107 | try { 108 | std::getline(std::cin, line); 109 | } 110 | catch(std::exception &e) { 111 | return -1; 112 | } 113 | return (line.length() == 1 ? *(line.c_str()) : 0); 114 | } 115 | 116 | void configureAudioInput() { 117 | std::vector devices = m_host.getAudioInDevices(); 118 | if (devices.size()) { 119 | std::cout << "\nSelect from the following:" << std::endl; 120 | for (int i = 0; i < devices.size(); i++) { 121 | std::cout << "[" << i << "]: " << devices[i] << std::endl; 122 | } 123 | std::cout << "\n[0 - " << devices.size()-1 << "]: "; 124 | int device = getchar() - 48; 125 | if (!setAudioInput(device)) { 126 | m_settings.set("AudioInput", devices[device]); 127 | } 128 | } else { 129 | std::cout << "\nNo audio input devices." << std::endl; 130 | } 131 | } 132 | 133 | int setAudioInput(int device) { 134 | if (!m_host.setAudioInDevice(device)) { 135 | restart(); 136 | return 0; 137 | } 138 | return -1; 139 | } 140 | 141 | void configureAudioOutput() { 142 | std::vector devices = m_host.getAudioOutDevices(); 143 | if (devices.size()) { 144 | std::cout << "\nSelect from the following:" << std::endl; 145 | for (int i = 0; i < devices.size(); i++) { 146 | std::cout << "[" << i << "]: " << devices[i] << std::endl; 147 | } 148 | std::cout << "\n[0 - " << devices.size()-1 << "]: "; 149 | int device = getchar() - 48; 150 | if (!setAudioOutput(device)) { 151 | m_settings.set("AudioOutput", devices[device]); 152 | } 153 | } else { 154 | std::cout << "\nNo audio output devices." << std::endl; 155 | } 156 | } 157 | 158 | int setAudioOutput(int device) { 159 | if (!m_host.setAudioOutDevice(device)) { 160 | restart(); 161 | return 0; 162 | } 163 | return -1; 164 | } 165 | 166 | /* 167 | void configureMidiInput() { 168 | std::vector ports = m_host.getMidiInPorts(); 169 | if (ports.size()) { 170 | std::cout << "\nSelect from the following:" << std::endl; 171 | for (int i = 0; i < ports.size(); i++) { 172 | std::cout << "[" << i << "]: " << ports[i] << std::endl; 173 | } 174 | std::cout << "\n[0 - " << ports.size()-1 << "]: "; 175 | int port = getchar() - 48; 176 | if (!setMidiInput(port)) { 177 | m_settings.set("MidiInput", ports[port]); 178 | } 179 | } else { 180 | std::cout << "\nNo MIDI input devices." << std::endl; 181 | } 182 | } 183 | 184 | int setMidiInput(int port) { 185 | if (!m_host.setMidiInPort(port)) { 186 | restart(); 187 | return 0; 188 | } 189 | return -1; 190 | } 191 | 192 | void configureMidiOutput() { 193 | std::vector ports = m_host.getMidiOutPorts(); 194 | if (ports.size()) { 195 | std::cout << "\nSelect from the following:" << std::endl; 196 | for (int i = 0; i < ports.size(); i++) { 197 | std::cout << "[" << i << "]: " << ports[i] << std::endl; 198 | } 199 | std::cout << "\n[0 - " << ports.size()-1 << "]: "; 200 | int port = getchar() - 48; 201 | if (!setMidiOutput(port)) { 202 | m_settings.set("MidiOutput", ports[port]); 203 | } 204 | } else { 205 | std::cout << "\nNo MIDI output devices." << std::endl; 206 | } 207 | } 208 | 209 | int setMidiOutput(int port) { 210 | if (!m_host.setMidiOutPort(port)) { 211 | restart(); 212 | return 0; 213 | } 214 | return -1; 215 | } 216 | */ 217 | 218 | void modifyParameter() { 219 | std::vector params = m_host.getParameters(); 220 | if (params.size()) { 221 | while (1) { 222 | std::cout << "\nSelect from the following:" << std::endl; 223 | for (int i = 0; i < params.size(); i++) { 224 | std::cout << "[" << i << "] " << params[i] << std::endl; 225 | } 226 | std::cout << "[b] Back to Main Menu" << std::endl; 227 | std::cout << "\n[0 - " << params.size()-1 << ", b]: "; 228 | 229 | int index = getchar(); 230 | if (index != 'b') { 231 | index -= 48; 232 | if (index < params.size()) { 233 | t_param val = m_host.getParameterValue(index); 234 | std::cout << "\nCurrent value: " << val << ". New value?: "; 235 | std::string newvalstr; 236 | std::getline(std::cin, newvalstr); 237 | if (!newvalstr.empty()) { 238 | try { 239 | double newval = std::stod(newvalstr); 240 | t_param min, max; 241 | m_host.getParameterMinMax(index, &min, &max); 242 | newval = (newval < min) ? min : (newval > max) ? max : newval; 243 | m_host.setParameterValue(index, t_param(newval)); 244 | } 245 | catch(std::exception &e) { 246 | std::cout << "\nI take exception!" << std::endl; 247 | } 248 | } 249 | } 250 | } else break; 251 | } 252 | } else { 253 | std::cout << "\nNo parameters." << std::endl; 254 | } 255 | } 256 | 257 | void restart() { 258 | m_host.restart(); 259 | run(); 260 | } 261 | 262 | void setupSettings() { 263 | std::string filepath(m_workingPath + "prefs.json"); 264 | std::ifstream file(filepath); 265 | std::string content(std::istreambuf_iterator(file), (std::istreambuf_iterator()) ); 266 | 267 | if (!m_settings.parseText(content)) return; 268 | 269 | std::string value; 270 | if (!m_settings.get("AudioInput", &value)) { 271 | std::vector devices = m_host.getAudioInDevices(); 272 | for (int i = 0, size = devices.size(); i < size; i++) { 273 | if (devices[i] == value) { 274 | setAudioInput(i); 275 | std::cout << "Setting audio input from settings: " << value << std::endl; 276 | break; 277 | } 278 | } 279 | } 280 | if (!m_settings.get("AudioOutput", &value)) { 281 | std::vector devices = m_host.getAudioOutDevices(); 282 | for (int i = 0, size = devices.size(); i < size; i++) { 283 | if (devices[i] == value) { 284 | setAudioOutput(i); 285 | std::cout << "Setting audio output from settings: " << value << std::endl; 286 | break; 287 | } 288 | } 289 | } 290 | /* 291 | if (!m_settings.get("MidiInput", &value)) { 292 | std::vector ports = m_host.getMidiInPorts(); 293 | for (int i = 0, size = ports.size(); i < size; i++) { 294 | if (ports[i] == value) { 295 | setMidiInput(i); 296 | std::cout << "Setting midi input from settings: " << value << std::endl; 297 | break; 298 | } 299 | } 300 | } 301 | if (!m_settings.get("MidiOutput", &value)) { 302 | std::vector ports = m_host.getMidiOutPorts(); 303 | for (int i = 0, size = ports.size(); i < size; i++) { 304 | if (ports[i] == value) { 305 | setMidiOutput(i); 306 | std::cout << "Setting midi output from settings: " << value << std::endl; 307 | break; 308 | } 309 | } 310 | } 311 | */ 312 | } 313 | 314 | void shutdownSettings() { 315 | std::string filepath(m_workingPath + "prefs.json"); 316 | std::ofstream ofstr(filepath); 317 | ofstr << m_settings; 318 | } 319 | 320 | enum mappingType { 321 | LINEAR, 322 | EXPONENTIAL, 323 | LOG, 324 | LUT, // ? 325 | }; 326 | 327 | struct interfaceMapping { 328 | std::string src; // interface element name (e.g. hardware device 'encoder1') 329 | std::string dst; // parameter target, this will need to be unique for now, or do we want to have a "mix" stage for this stuff? 330 | mappingType type; 331 | //std::string expr; // expression-based rule (e.g. if $dial1 == 0 then $frequency else $q) 332 | }; 333 | 334 | // this will retrieve exactly one hardware encoder, could be modified 335 | HardwareEncoder* getHardware() { 336 | std::string filepath(m_workingPath + "hardware.json"); 337 | std::ifstream file(filepath); 338 | std::string content(std::istreambuf_iterator(file), (std::istreambuf_iterator()) ); 339 | std::vector paramNames = m_host.getParameters(); 340 | 341 | if (!m_settings.parseText(content)) return nullptr; 342 | 343 | Settings devices; 344 | Settings mappings; 345 | if (!m_settings.get("devices", &devices) && !m_settings.get("mappings", &mappings)) { 346 | std::vector deviceKeys = devices.getKeys(); 347 | std::vector mapKeys = mappings.getKeys(); 348 | 349 | for (auto it = mapKeys.begin(); it != mapKeys.end(); it++) { 350 | std::string mapName = *it; 351 | Settings mapSettings; 352 | if (!mappings.get(mapName, &mapSettings)) { 353 | std::string mapSrc, mapDst; 354 | if (!mapSettings.get("src", &mapSrc) && !mapSettings.get("dst", &mapDst)) { 355 | auto deviceFound = std::find(deviceKeys.begin(), deviceKeys.end(), mapSrc); 356 | auto paramFound = std::find(paramNames.begin(), paramNames.end(), mapDst); 357 | 358 | if (deviceFound != deviceKeys.end() && paramFound != paramNames.end()) { 359 | Settings deviceSettings; 360 | if (!devices.get(mapSrc, &deviceSettings)) { 361 | std::string deviceType; 362 | if (!deviceSettings.get("type", &deviceType)) { 363 | if (deviceType == "encoder") { 364 | int pin1, pin2; 365 | if (!deviceSettings.get("pin1", &pin1) && !deviceSettings.get("pin2", &pin2)) { 366 | if (!m_encoder) { 367 | return new HardwareEncoder(paramFound - paramNames.begin(), pin1, pin2); 368 | } 369 | } 370 | } 371 | else { 372 | ; // encoders are the only kind of hardware we know about right now 373 | } 374 | } 375 | } 376 | } 377 | } 378 | } 379 | } 380 | } 381 | return nullptr; 382 | } 383 | 384 | Host m_host; 385 | Settings m_settings; 386 | std::string m_workingPath; 387 | HardwareEncoder* m_encoder; 388 | 389 | }; 390 | 391 | static std::string getWorkingPath(int argc, const char* argv[]) { 392 | if (argc < 1) 393 | throw std::invalid_argument("argument missing for path to binary"); 394 | 395 | std::string pstr; 396 | char* cstr = realpath(argv[0], nullptr); 397 | if (cstr) { 398 | pstr = cstr; 399 | free(cstr); 400 | } else { 401 | throw std::invalid_argument("could not get realpath"); 402 | } 403 | 404 | char* tstr = new char[pstr.length() + 1]; 405 | char* c; 406 | 407 | strncpy(tstr, pstr.c_str(), pstr.length() + 1); 408 | c = strrchr(tstr, '/'); 409 | if (!c) 410 | throw std::invalid_argument("cannot parse path separators"); 411 | *c = 0; // slice off the executable to get just the build folder 412 | 413 | pstr = tstr; 414 | pstr += "/"; 415 | 416 | delete[] tstr; 417 | 418 | // std::cout << "working-path is " << pstr << std::endl; 419 | 420 | return pstr; 421 | } 422 | 423 | } 424 | 425 | #endif 426 | -------------------------------------------------------------------------------- /include/Globals.h: -------------------------------------------------------------------------------- 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 | #ifndef _Globals_h_ 25 | #define _Globals_h_ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | namespace GenPi { 34 | 35 | struct Globals { 36 | constexpr static const double sampleRate = 48000.; 37 | constexpr static const size_t blockSize = 32; 38 | 39 | #ifdef GENLIB_USE_FLOAT32 40 | constexpr static const size_t floatBits = 32; 41 | #else 42 | constexpr static const size_t floatBits = 64; 43 | #endif 44 | }; 45 | 46 | } 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/HardwareEncoder.h: -------------------------------------------------------------------------------- 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 | #ifndef _HardwareEncoder_h_ 25 | #define _HardwareEncoder_h_ 26 | 27 | #if defined(RASPI) && defined(WIRINGPI) 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "Object.h" 34 | 35 | struct encoder; 36 | extern "C" struct encoder* setupencoder(int pin_a, int pin_b); 37 | 38 | extern "C" { 39 | #include "rotaryencoder.h" 40 | } 41 | 42 | namespace GenPi { 43 | 44 | class HardwareEncoder { 45 | 46 | public: 47 | 48 | HardwareEncoder( 49 | int paramIndex = -1, // we want to provide a name-based automapping, as well 50 | int pin1 = 3, // pins are wiringPi-numbered 51 | int pin2 = 4) 52 | : mSampleThread(&HardwareEncoder::sample, this) 53 | , mEncoder(nullptr) 54 | , mCurrentValue(INT_MAX) 55 | , mParameterIndex(paramIndex) 56 | { 57 | wiringPiSetup(); // initialize the wiringPi library. 58 | // NOTE: this requires root, absurdly. There is a better way to handle this 59 | // but it requires calling the 'gpio' utility via system() to configure the 60 | // pins on the fly, and is more than I want to deal with for a proof of concept 61 | // implementation right now. http://wiringpi.com/reference/setup/ 62 | mEncoder = setupencoder(pin1, pin2); 63 | if (paramIndex >= 0) { 64 | mRunning = true; 65 | } 66 | } 67 | 68 | 69 | ~HardwareEncoder() { 70 | mRunning = false; 71 | if (mSampleThread.joinable()) 72 | mSampleThread.join(); 73 | } 74 | 75 | void setParameter(int index) { 76 | if (index >= 0) { 77 | if (index < getGenObject().getNumParameters()) { 78 | mParameterIndex = index; 79 | mRunning = true; 80 | } // else no change 81 | } 82 | else { 83 | mParameterIndex = -1; 84 | mRunning = false; 85 | } 86 | } 87 | 88 | private: 89 | 90 | void sample() { 91 | while (mRunning) { 92 | if (mEncoder) { 93 | // endless encoder logic 94 | int value = getEncoderValue(mEncoder); 95 | 96 | if (value != mCurrentValue) { 97 | t_param fdelta = (t_param)(value - mCurrentValue); 98 | t_param curvalue, fvalue, min, max; 99 | // printf("DEBUG: got encoder value %d (delta %0.3f)\n", value, fdelta); 100 | curvalue = getGenObject().getParameterValue(mParameterIndex); 101 | fvalue = curvalue; 102 | if (!getGenObject().getParameterMinMax(mParameterIndex, &min, &max)) { 103 | t_param stepsize = (max - min) / 127.; 104 | fdelta *= stepsize; 105 | fvalue += fdelta; 106 | fvalue = fvalue < min ? min : fvalue > max ? max : fvalue; 107 | } else { 108 | fvalue += fdelta; 109 | } 110 | if (fvalue != curvalue) { 111 | getGenObject().setParameterValue(mParameterIndex, fvalue); 112 | // printf("DEBUG: sending value %0.3f\n", fvalue); 113 | } 114 | mCurrentValue = value; 115 | } 116 | } 117 | usleep(100); 118 | } 119 | } 120 | 121 | int getEncoderValue(struct encoder* enc) { 122 | return enc->value; 123 | } 124 | 125 | std::thread mSampleThread; 126 | struct encoder *mEncoder; 127 | bool mRunning; 128 | int mCurrentValue; 129 | int mParameterIndex; 130 | 131 | }; 132 | 133 | // wiringPi definitions of INPUT and OUTPUT will interfere with RtAudio 134 | #undef INPUT 135 | #undef OUTPUT 136 | 137 | } // namespace GenPi 138 | 139 | #else 140 | 141 | namespace GenPi { 142 | 143 | class HardwareEncoder { // dummy 144 | 145 | public: 146 | HardwareEncoder(int paramIndex = 0, 147 | int pin1 = 3, 148 | int pin2 = 4) 149 | { 150 | } 151 | 152 | }; 153 | 154 | } 155 | 156 | #endif 157 | #endif 158 | -------------------------------------------------------------------------------- /include/Host.h: -------------------------------------------------------------------------------- 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 | #ifndef _Host_h_ 25 | #define _Host_h_ 26 | 27 | #include "gen_exported.h" 28 | #include "AudioMidiHost.h" 29 | #include "ParameterHost.h" 30 | 31 | // composed class for audio/midi hosting + parameter support 32 | 33 | namespace GenPi { 34 | 35 | template 36 | class Host { 37 | static_assert(std::is_base_of::value, "Host template parameter must derive from AudioMidiHost"); 38 | 39 | public: 40 | Host() {} 41 | ~Host() {} 42 | 43 | // AudioMidiHost 44 | int setup() { return m_audio_host.setup(); } 45 | int run() { return m_audio_host.run(); } 46 | void shutdown() { m_audio_host.shutdown(); } 47 | int restart() { return m_audio_host.restart(); } 48 | std::vector getAudioInDevices() { return m_audio_host.getAudioInDevices(); } 49 | int setAudioInDevice(int device) { return m_audio_host.setAudioInDevice(device); } 50 | std::vector getAudioOutDevices() { return m_audio_host.getAudioOutDevices(); } 51 | int setAudioOutDevice(int device) { return m_audio_host.setAudioOutDevice(device); } 52 | std::vector getMidiInPorts() const { return m_audio_host.getMidiInPorts(); } 53 | int setMidiInPort(int port) { return m_audio_host.setMidiInPort(port); } 54 | std::vector getMidiOutPorts() const { return m_audio_host.getMidiOutPorts(); } 55 | int setMidiOutPort(int port) { return m_audio_host.setMidiOutPort(port); } 56 | std::string getName() const { return m_audio_host.getName(); } 57 | 58 | // ParameterHost 59 | std::vector getParameters() const { return m_param_host.getParameters(); } 60 | int getParameterMinMax(int index, t_param* min, t_param* max) const { return m_param_host.getParameterMinMax(index, min, max); } 61 | t_param getParameterValue(int index) const { return m_param_host.getParameterValue(index); } 62 | void setParameterValue(int index, t_param value) { m_param_host.setParameterValue(index, value); } 63 | 64 | private: 65 | C m_audio_host; 66 | ParameterHost m_param_host; 67 | 68 | }; 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/Object.h: -------------------------------------------------------------------------------- 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 | #ifndef _Object_h_ 25 | #define _Object_h_ 26 | 27 | #include "Globals.h" 28 | #include "gen_exported.h" 29 | 30 | using namespace gen_exported; 31 | 32 | namespace GenPi { 33 | 34 | class Object { 35 | 36 | public: 37 | static Object& getInstance() { 38 | static Object theInstance; 39 | pInstance = &theInstance; 40 | return *pInstance; 41 | } 42 | 43 | int getNumParameters() { return num_params(); } 44 | int getNumInputChannels() { return num_inputs(); } 45 | int getNumOutputChannels() { return num_outputs(); } 46 | 47 | const char* getParameterName(long index) { 48 | if (m_genObject && index >= 0 && index < getNumParameters()) { 49 | return getparametername(m_genObject, index); 50 | } 51 | return ""; 52 | } 53 | 54 | int getParameterMinMax(long index, t_param* min, t_param* max) { 55 | if (m_genObject && index >= 0 && index < getNumParameters()) { 56 | if (getparameterhasminmax(m_genObject, index)) { 57 | *min = getparametermin(m_genObject, index); 58 | *max = getparametermax(m_genObject, index); 59 | return 0; 60 | } 61 | } 62 | return -1; 63 | } 64 | 65 | t_param getParameterValue(long index) { 66 | if (m_genObject && index >= 0 && index < getNumParameters()) { 67 | t_param value; 68 | getparameter(m_genObject, index, &value); 69 | return value; 70 | } 71 | return -1; 72 | } 73 | 74 | void setParameterValue(long index, t_param value) { 75 | if (m_genObject && index >= 0 && index < getNumParameters()) { 76 | setparameter(m_genObject, index, value, nullptr); 77 | } 78 | } 79 | 80 | void process(t_sample** ins, long numIns, t_sample** outs, long numOuts, long numFrames) { 81 | if (m_genObject) { 82 | perform(m_genObject, ins, numIns, outs, numOuts, numFrames); 83 | } 84 | } 85 | 86 | private: 87 | 88 | static Object *pInstance; 89 | 90 | Object() { 91 | m_genObject = (CommonState*)create(Globals::sampleRate, Globals::blockSize); 92 | } 93 | 94 | Object(const Object& rs) { 95 | pInstance = rs.pInstance; 96 | } 97 | 98 | Object &operator = (const Object& rs) { 99 | if (this != &rs) { 100 | pInstance = rs.pInstance; 101 | } 102 | return *this; 103 | } 104 | 105 | ~Object() { 106 | if (m_genObject) { 107 | destroy(m_genObject); 108 | } 109 | } 110 | 111 | CommonState* m_genObject; 112 | 113 | }; 114 | 115 | static inline Object& getGenObject() { 116 | return Object::getInstance(); 117 | } 118 | 119 | } 120 | 121 | #endif 122 | -------------------------------------------------------------------------------- /include/ParameterHost.h: -------------------------------------------------------------------------------- 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 | #ifndef _ParameterHost_h_ 25 | #define _ParameterHost_h_ 26 | 27 | #include "Object.h" 28 | 29 | namespace GenPi { 30 | 31 | class ParameterHost { 32 | 33 | public: 34 | std::vector getParameters() const { 35 | std::vector parameters; 36 | long numParams = getGenObject().getNumParameters(); 37 | for (int i = 0; i < numParams; i++) { 38 | const char* name = getGenObject().getParameterName(i); 39 | if (!name) name = ""; 40 | parameters.push_back(name); 41 | } 42 | return parameters; 43 | } 44 | 45 | int getParameterMinMax(int index, t_param* min, t_param* max) const { 46 | return getGenObject().getParameterMinMax(index, min, max); 47 | } 48 | 49 | t_param getParameterValue(int index) const { 50 | return getGenObject().getParameterValue(index); 51 | } 52 | 53 | void setParameterValue(int index, t_param value) { 54 | getGenObject().setParameterValue(index, value); 55 | } 56 | 57 | private: 58 | 59 | }; 60 | 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/Processor.h: -------------------------------------------------------------------------------- 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 | #ifndef _Processor_h_ 25 | #define _Processor_h_ 26 | 27 | #include "GenPi.h" 28 | #include "Object.h" 29 | 30 | namespace GenPi { 31 | 32 | class Processor { 33 | 34 | public: 35 | Processor() {} 36 | ~Processor() {} 37 | 38 | void prepare(double sampleRate, size_t blockSize) { 39 | ; 40 | } 41 | 42 | void process(t_sample** audioInputs, size_t numInputs, 43 | t_sample** audioOutputs, size_t numOutputs, 44 | size_t sampleFrames) 45 | { 46 | // assuming non-interleaved sample buffers 47 | int obIns = getGenObject().getNumInputChannels(); 48 | int obOuts = getGenObject().getNumOutputChannels(); 49 | getGenObject().process(obIns ? audioInputs : nullptr, obIns ? numInputs : 0, 50 | obOuts ? audioOutputs : nullptr, obOuts ? numOutputs : 0, 51 | sampleFrames); 52 | } 53 | 54 | }; 55 | 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/RtAudioMidiHost.h: -------------------------------------------------------------------------------- 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 | #ifndef _RtAudioMidiHost_h_ 25 | #define _RtAudioMidiHost_h_ 26 | 27 | #include "GenPi.h" 28 | #include "RtAudio.h" 29 | #include "RtMidi.h" 30 | #include "AudioMidiHost.h" 31 | #include "Processor.h" 32 | 33 | // audio-driven audio + midi host 34 | 35 | namespace GenPi { 36 | 37 | class RtAudioMidiHost : public AudioMidiHost { 38 | 39 | public: 40 | // TODO separate class creation/setup/run/shutdown into separate operations 41 | RtAudioMidiHost() : 42 | m_audio(nullptr), 43 | m_ip(nullptr), m_op(nullptr) { 44 | if (init()) { 45 | if (m_audio) { 46 | m_info.audioInDevice = m_audio->getDefaultInputDevice(); 47 | m_info.audioOutDevice = m_audio->getDefaultOutputDevice(); 48 | } 49 | } 50 | } 51 | 52 | // can we add these to the base class somehow? 53 | RtAudioMidiHost(RtAudioMidiHost const &) = delete; 54 | void operator=(RtAudioMidiHost const &) = delete; 55 | 56 | enum AudioDeviceType { 57 | Input, 58 | Output, 59 | All 60 | }; 61 | 62 | virtual std::vector getAudioInDevices() const { 63 | return getAudioDevices(Input); 64 | } 65 | 66 | virtual int setAudioInDevice(int device) { 67 | int rv = -1; 68 | std::vector devices = getAudioInDevices(); 69 | if (device >= 0 && device < devices.size()) { 70 | std::string deviceName = devices[device]; 71 | std::vector all = getAudioDevices(All); 72 | for (int i = 0, size = all.size(); i < size; i++) { 73 | if (all[i] == deviceName) { 74 | m_info.audioInDevice = i; 75 | rv = 0; 76 | break; 77 | } 78 | } 79 | } 80 | return rv; 81 | } 82 | 83 | virtual std::vector getAudioOutDevices() const { 84 | return getAudioDevices(Output); 85 | } 86 | 87 | virtual int setAudioOutDevice(int device) { 88 | int rv = -1; 89 | std::vector devices = getAudioOutDevices(); 90 | if (device >= 0 && device < devices.size()) { 91 | std::string deviceName = devices[device]; 92 | std::vector all = getAudioDevices(All); 93 | for (int i = 0, size = all.size(); i < size; i++) { 94 | if (all[i] == deviceName) { 95 | m_info.audioOutDevice = i; 96 | rv = 0; 97 | break; 98 | } 99 | } 100 | } 101 | return rv; 102 | } 103 | 104 | virtual int setup() { 105 | RtAudio::StreamParameters iParams; 106 | iParams.deviceId = m_info.audioInDevice; 107 | iParams.nChannels = m_info.numChannels; 108 | iParams.firstChannel = 0; // offset 109 | 110 | RtAudio::StreamParameters oParams; 111 | oParams.deviceId = m_info.audioOutDevice; 112 | oParams.nChannels = m_info.numChannels; 113 | oParams.firstChannel = 0; // offset 114 | 115 | RtAudio::StreamOptions options; 116 | options.flags = RTAUDIO_NONINTERLEAVED 117 | | RTAUDIO_MINIMIZE_LATENCY 118 | | RTAUDIO_SCHEDULE_REALTIME 119 | ; 120 | options.priority = 1; // goes with RTAUDIO_SCHEDULE_REALTIME 121 | #ifdef LINUX // this appears to be necessary, needs further investigation since I was testing in a VM 122 | options.numberOfBuffers = 16; 123 | #endif 124 | try { 125 | unsigned int sampleRate = (unsigned int)Globals::sampleRate; 126 | unsigned int bufferFrames = (unsigned int)Globals::blockSize; 127 | unsigned int inputDeviceCount = getAudioInDevices().size(); 128 | unsigned int outputDeviceCount = getAudioOutDevices().size(); 129 | #if 0 130 | RtAudio::DeviceInfo info = m_audio->getDeviceInfo(0); 131 | std::cout << "\n" << info.name << ", supports " << info.inputChannels << " input channels and " << info.outputChannels << " output channels. " << info.preferredSampleRate << " is the preferred sample rate." << std::endl; 132 | #endif 133 | m_audio->openStream(outputDeviceCount > 0 ? &oParams : nullptr, 134 | inputDeviceCount > 0 ? &iParams : nullptr, 135 | Globals::floatBits == 32 ? RTAUDIO_FLOAT32 : RTAUDIO_FLOAT64, 136 | sampleRate, &bufferFrames, callback, 137 | this /*userData*/, &options, nullptr /*errorCallback*/); 138 | 139 | // TODO: this line is necessary on RasPi to avoid a crash, but not on OSX 140 | // would be good to understand why :: probably because RasPi has a larger 141 | // minimum buffer, therefore overrunning our default 32 frames. 142 | if (bufferFrames != (unsigned int)Globals::blockSize) { 143 | m_processor.prepare((double)sampleRate, (size_t)bufferFrames); 144 | } 145 | if (!(options.flags & RTAUDIO_NONINTERLEAVED)) { 146 | m_info.audioInterleaved = true; 147 | // allocate non-interleaved buffers 148 | m_ip = new t_sample[bufferFrames * m_info.numChannels]; 149 | m_op = new t_sample[bufferFrames * m_info.numChannels]; 150 | } else { 151 | m_info.audioInterleaved = false; 152 | } 153 | } 154 | catch (RtAudioError& e) { 155 | std::cout << "\n" << e.getMessage() << "\n" << std::endl; 156 | return -1; 157 | } 158 | return 0; 159 | } 160 | 161 | virtual int run() { 162 | 163 | if (m_audio && (!m_audio->isStreamOpen() || m_audio->isStreamRunning())) return 0; 164 | 165 | try { 166 | m_audio->startStream(); 167 | } 168 | catch (RtAudioError& e) { 169 | std::cout << "\n" << e.getMessage() << "\n" << std::endl; 170 | return -1; 171 | } 172 | return 0; 173 | } 174 | 175 | virtual void shutdown() { 176 | if (m_audio) { 177 | if (m_audio->isStreamRunning()) { 178 | m_audio->abortStream(); 179 | } 180 | if (m_audio->isStreamOpen()) { 181 | m_audio->closeStream(); 182 | } 183 | delete m_audio; 184 | m_audio = nullptr; 185 | } 186 | 187 | if (m_ip) { 188 | delete[] m_ip; 189 | m_ip = nullptr; 190 | } 191 | if (m_op) { 192 | delete[] m_op; 193 | m_op = nullptr; 194 | } 195 | } 196 | 197 | virtual int restart() { 198 | if (!m_audio || !m_audio->isStreamOpen()) return -1; // we're not inited yet 199 | 200 | int rv = 0; 201 | shutdown(); 202 | if (init()) { 203 | setup(); 204 | } else rv = -1; 205 | return rv; 206 | } 207 | 208 | virtual ~RtAudioMidiHost() { 209 | shutdown(); 210 | } 211 | 212 | virtual std::string getName() const { return "RtAudio"; } 213 | 214 | virtual std::vector getMidiInPorts() const { std::vector ports; return ports; } 215 | virtual int setMidiInPort(int port) { return -1; } 216 | 217 | virtual std::vector getMidiOutPorts() const { std::vector ports; return ports; } 218 | virtual int setMidiOutPort(int port) { return -1; } 219 | 220 | private: 221 | struct RtAudioMidiInfo { 222 | int audioInDevice; 223 | int audioOutDevice; 224 | int numChannels; 225 | bool audioInterleaved; 226 | 227 | RtAudioMidiInfo() : 228 | audioInDevice(0), 229 | audioOutDevice(0), 230 | numChannels(2), 231 | audioInterleaved(false) {} 232 | }; 233 | 234 | static int callback(void* outputBuffer, void* inputBuffer, 235 | unsigned int nFrames, 236 | double streamTime, 237 | RtAudioStreamStatus status, 238 | void *userData) 239 | { 240 | RtAudioMidiHost* rth = (RtAudioMidiHost *)userData; 241 | 242 | t_sample* ip[rth->m_info.numChannels]; 243 | t_sample* op[rth->m_info.numChannels]; 244 | 245 | if (rth->m_info.audioInterleaved) { 246 | // perform an de-interleave 247 | for (int i = 0; i < rth->m_info.numChannels; i++) { 248 | ip[i] = rth->m_ip + (i * nFrames); 249 | op[i] = rth->m_op + (i * nFrames); 250 | for (int j = 0; j < nFrames; j++) { 251 | ip[i][j] = ((t_sample *)inputBuffer)[(j * rth->m_info.numChannels) + i]; 252 | } 253 | } 254 | } else { 255 | // we are already deinterleaved, just set up the pointers 256 | for (int i = 0; i < rth->m_info.numChannels; i++) { 257 | ip[i] = (t_sample*)inputBuffer + (i * nFrames); 258 | op[i] = (t_sample*)outputBuffer + (i * nFrames); 259 | } 260 | } 261 | 262 | rth->m_processor.process((t_sample**)ip, rth->m_info.numChannels, 263 | (t_sample**)op, rth->m_info.numChannels, 264 | nFrames); 265 | 266 | if (rth->m_info.audioInterleaved) { 267 | // perform an interleave 268 | for (int i = 0; i < rth->m_info.numChannels; i++) { 269 | for (int j = 0; j < nFrames; j++) { 270 | ((t_sample *)outputBuffer)[(j * rth->m_info.numChannels) + i] = op[i][j]; 271 | } 272 | } 273 | } 274 | 275 | return 0; // keep going 276 | } 277 | 278 | bool init() { 279 | RtAudio::Api api = RtAudio::UNSPECIFIED; 280 | 281 | #ifdef RASPI 282 | api = RtAudio::LINUX_ALSA; 283 | #endif 284 | if (!initAudio(api)) { 285 | return false; 286 | } 287 | 288 | return true; 289 | } 290 | 291 | bool initAudio(RtAudio::Api api) { 292 | try { 293 | m_audio = new RtAudio(api); 294 | } 295 | catch(RtAudioError& e) { 296 | std::cout << "\nCould not create RtAudio device!\n" << e.getMessage() << std::endl; 297 | return false; 298 | } 299 | if (m_audio->getDeviceCount() < 1) { 300 | std::cout << "\nNo audio devices found!" << std::endl;; 301 | delete m_audio; 302 | m_audio = nullptr; 303 | return false; 304 | } 305 | return true; 306 | } 307 | 308 | std::vector getAudioDevices(AudioDeviceType way) const { 309 | std::vector devices; 310 | if (m_audio) { 311 | int ct = m_audio->getDeviceCount(); 312 | for (int i = 0; i < ct; i++) { 313 | try { 314 | RtAudio::DeviceInfo info = m_audio->getDeviceInfo(i); 315 | if ( 316 | (way == Input && info.inputChannels) 317 | || (way == Output && info.outputChannels) 318 | || (way == All)) 319 | { 320 | devices.push_back(info.name); 321 | } 322 | } 323 | catch(RtAudioError& e) { 324 | std::cout << "\n" << e.getMessage() << "\n" << std::endl; 325 | devices.push_back(""); 326 | } 327 | } 328 | } 329 | return devices; 330 | } 331 | 332 | RtAudio* m_audio; // pointers due to possible throw in constructor 333 | Processor m_processor; 334 | t_sample* m_ip; 335 | t_sample* m_op; 336 | RtAudioMidiInfo m_info; 337 | 338 | }; 339 | 340 | } 341 | 342 | #endif 343 | -------------------------------------------------------------------------------- /include/Settings.h: -------------------------------------------------------------------------------- 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 | #ifndef _Settings_h_ 25 | #define _Settings_h_ 26 | 27 | #include "jsonxx.h" 28 | 29 | namespace GenPi { 30 | 31 | class Settings { 32 | 33 | public: 34 | 35 | Settings() {} 36 | ~Settings() {} 37 | 38 | template 39 | void set(std::string key, const T& value) { m_state << key << value; } 40 | // override for the Settings case 41 | void set(std::string key, const Settings& value) { m_state << key << value.m_state; } 42 | 43 | bool parseText(std::string& text) { return m_state.parse(text); } 44 | std::string getText() const { return m_state.json(); } 45 | 46 | int get(std::string key, std::string* value) const { return get(key, value); } 47 | int get(std::string key, int* value) const { return get(key, value); } 48 | int get(std::string key, double* value) const { return get(key, value); } 49 | int get(std::string key, bool* value) const { return get(key, value); } 50 | int get(std::string key, Settings* value) const { return get(key, value); } 51 | 52 | std::vector getKeys() { 53 | std::vector keys; 54 | jsonxx::Object::container container = m_state.kv_map(); 55 | for (auto it = container.begin(); it != container.end(); it++) { 56 | keys.push_back(it->first); 57 | } 58 | return keys; 59 | } 60 | 61 | bool empty() { return m_state.empty(); } 62 | 63 | // currently not necessary, but might be at some point 64 | friend std::ostream& operator<<(std::ostream& os, const Settings& obj); 65 | friend std::istream& operator>>(std::istream& is, Settings& obj); 66 | 67 | private: 68 | 69 | Settings(jsonxx::Object& o) : m_state(o) {} 70 | Settings& operator=(const jsonxx::Object& o) { 71 | m_state = o; 72 | return *this; 73 | } 74 | 75 | template 76 | int get(std::string key, T* value) const { 77 | if (m_state.has(key)) { 78 | *value = (U)m_state.get(key); 79 | return 0; 80 | } 81 | return -1; 82 | } 83 | 84 | jsonxx::Object m_state; 85 | 86 | }; 87 | 88 | std::ostream& operator<<(std::ostream& os, const Settings& obj) { 89 | os << obj.getText(); 90 | return os; 91 | } 92 | 93 | std::istream& operator>>(std::istream& is, Settings& obj) { 94 | std::string s(std::istreambuf_iterator(is), {}); 95 | if (!obj.parseText(s)) { 96 | is.setstate(std::ios::failbit); 97 | } 98 | return is; 99 | } 100 | 101 | } 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /include/gen_exported.h: -------------------------------------------------------------------------------- 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 (at) 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 | 25 | #include "genlib.h" 26 | #include "genlib_exportfunctions.h" 27 | #include "genlib_ops.h" 28 | 29 | namespace gen_exported { 30 | 31 | int num_inputs(); 32 | int num_outputs(); 33 | int num_params(); 34 | int perform(CommonState *cself, t_sample **ins, long numins, t_sample **outs, long numouts, long n); 35 | void reset(CommonState *cself); 36 | void setparameter(CommonState *cself, long index, t_param value, void *ref); 37 | void getparameter(CommonState *cself, long index, t_param *value); 38 | const char *getparametername(CommonState *cself, long index); 39 | t_param getparametermin(CommonState *cself, long index); 40 | t_param getparametermax(CommonState *cself, long index); 41 | char getparameterhasminmax(CommonState *cself, long index); 42 | const char *getparameterunits(CommonState *cself, long index); 43 | size_t getstatesize(CommonState *cself); 44 | short getstate(CommonState *cself, char *state); 45 | short setstate(CommonState *cself, const char *state); 46 | void *create(t_param sr, long vs); 47 | void destroy(CommonState *cself); 48 | 49 | } // gen_exported:: 50 | -------------------------------------------------------------------------------- /src/Object.cpp: -------------------------------------------------------------------------------- 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 "Object.h" 25 | 26 | using namespace GenPi; 27 | 28 | Object* Object::pInstance = 0; 29 | -------------------------------------------------------------------------------- /src/gen_exported.cpp: -------------------------------------------------------------------------------- 1 | #include "gen_exported.h" 2 | 3 | namespace gen_exported { 4 | 5 | /******************************************************************************************************************* 6 | Cycling '74 License for Max-Generated Code for Export 7 | Copyright (c) 2016 Cycling '74 8 | The code that Max generates automatically and that end users are capable of exporting and using, and any 9 | associated documentation files (the “Software”) is a work of authorship for which Cycling '74 is the author 10 | and owner for copyright purposes. A license is hereby granted, free of charge, to any person obtaining a 11 | copy of the Software (“Licensee”) to use, copy, modify, merge, publish, and distribute copies of the Software, 12 | and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 13 | The Software is licensed to Licensee only for non-commercial use. Users who wish to make commercial use of the 14 | Software must contact the copyright owner to determine if a license for commercial use is available, and the 15 | terms and conditions for same, which may include fees or royalties. For commercial use, please send inquiries 16 | to licensing (at) cycling74.com. The determination of whether a use is commercial use or non-commercial use is based 17 | upon the use, not the user. The Software may be used by individuals, institutions, governments, corporations, or 18 | other business whether for-profit or non-profit so long as the use itself is not a commercialization of the 19 | materials or a use that generates or is intended to generate income, revenue, sales or profit. 20 | The above copyright notice and this license shall be included in all copies or substantial portions of the Software. 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO 22 | THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 23 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | *******************************************************************************************************************/ 27 | 28 | // global noise generator 29 | Noise noise; 30 | static const int GENLIB_LOOPCOUNT_BAIL = 100000; 31 | 32 | 33 | // The State struct contains all the state and procedures for the gendsp kernel 34 | typedef struct State { 35 | CommonState __commonstate; 36 | int __exception; 37 | int vectorsize; 38 | t_sample m_z_7; 39 | t_sample m_z_8; 40 | t_sample m_z_6; 41 | t_sample m_z_5; 42 | t_sample m_z_4; 43 | t_sample m_q_2; 44 | t_sample m_y_9; 45 | t_sample samplerate; 46 | t_sample m_freq_1; 47 | t_sample m_mf_10; 48 | // re-initialize all member variables; 49 | inline void reset(t_param __sr, int __vs) { 50 | __exception = 0; 51 | vectorsize = __vs; 52 | samplerate = __sr; 53 | m_freq_1 = 48; 54 | m_q_2 = 0.1; 55 | m_z_4 = 0; 56 | m_z_5 = 0; 57 | m_z_6 = 0; 58 | m_z_7 = 0; 59 | m_z_8 = 0; 60 | m_y_9 = 0; 61 | m_mf_10 = 0; 62 | genlib_reset_complete(this); 63 | 64 | }; 65 | // the signal processing routine; 66 | inline int perform(t_sample ** __ins, t_sample ** __outs, int __n) { 67 | vectorsize = __n; 68 | const t_sample * __in1 = __ins[0]; 69 | t_sample * __out1 = __outs[0]; 70 | t_sample * __out2 = __outs[1]; 71 | if (__exception) { 72 | return __exception; 73 | 74 | } else if (( (__in1 == 0) || (__out1 == 0) || (__out2 == 0) )) { 75 | __exception = GENLIB_ERR_NULL_BUFFER; 76 | return __exception; 77 | 78 | }; 79 | t_sample mtof_1 = mtof(m_freq_1, 440); 80 | t_sample max_3 = (samplerate * 0.25); 81 | t_sample cf = ((mtof_1 <= 20) ? 20 : ((mtof_1 >= max_3) ? max_3 : mtof_1)); 82 | t_sample res = ((m_q_2 <= 0) ? 0 : ((m_q_2 >= 1) ? 1 : m_q_2)); 83 | // the main sample loop; 84 | while ((__n--)) { 85 | const t_sample in1 = (*(__in1++)); 86 | t_sample expr_3 = moogLadder_d_d_d(in1, cf, res); 87 | t_sample out2 = expr_3; 88 | t_sample out1 = expr_3; 89 | // assign results to output buffer; 90 | (*(__out1++)) = out1; 91 | (*(__out2++)) = out2; 92 | 93 | }; 94 | return __exception; 95 | 96 | }; 97 | inline void set_freq(t_param _value) { 98 | m_freq_1 = (_value < 32 ? 32 : (_value > 96 ? 96 : _value)); 99 | }; 100 | inline void set_q(t_param _value) { 101 | m_q_2 = (_value < 0 ? 0 : (_value > 1 ? 1 : _value)); 102 | }; 103 | inline t_sample moogLadder_d_d_d(t_sample asig, t_sample cf, t_sample res) { 104 | int i2v = 40000; 105 | t_sample akfc = safediv(cf, (samplerate * 0.5)); 106 | t_sample akf = safediv(cf, samplerate); 107 | t_sample fcr = ((((1.873 * safepow(akfc, 3)) + (0.4955 * safepow(akfc, 2))) - (0.649 * akfc)) + 0.9988); 108 | t_sample acr = ((((-3.9364) * safepow(akfc, 2)) + (1.8409 * akfc)) + 0.9968); 109 | t_sample twovg = (i2v * (1 - exp(((((-2) * 3.1415926535898) * fcr) * akf)))); 110 | t_sample y1 = (m_z_4 + (twovg * (tanh(safediv((asig - (((4 * res) * m_mf_10) * acr)), i2v)) - tanh(safediv(m_z_4, i2v))))); 111 | m_z_4 = y1; 112 | t_sample y2 = (m_z_5 + (twovg * (tanh(safediv(y1, i2v)) - tanh(safediv(m_z_5, i2v))))); 113 | m_z_5 = y2; 114 | t_sample y3 = (m_z_6 + (twovg * (tanh(safediv(y2, i2v)) - tanh(safediv(m_z_6, i2v))))); 115 | m_z_6 = y3; 116 | m_y_9 = (m_z_7 + (twovg * (tanh(safediv(y3, i2v)) - tanh(safediv(m_z_7, i2v))))); 117 | m_z_7 = m_y_9; 118 | m_mf_10 = ((m_y_9 + m_z_8) * 0.5); 119 | m_z_8 = m_y_9; 120 | return m_mf_10; 121 | 122 | }; 123 | 124 | } State; 125 | 126 | 127 | /// 128 | /// Configuration for the genlib API 129 | /// 130 | 131 | /// Number of signal inputs and outputs 132 | 133 | int gen_kernel_numins = 1; 134 | int gen_kernel_numouts = 2; 135 | 136 | int num_inputs() { return gen_kernel_numins; } 137 | int num_outputs() { return gen_kernel_numouts; } 138 | int num_params() { return 2; } 139 | 140 | /// Assistive lables for the signal inputs and outputs 141 | 142 | const char *gen_kernel_innames[] = { "audio signal input" }; 143 | const char *gen_kernel_outnames[] = { "moogLadder signal output L", "moogLadder signal output R" }; 144 | 145 | /// Invoke the signal process of a State object 146 | 147 | int perform(CommonState *cself, t_sample **ins, long numins, t_sample **outs, long numouts, long n) { 148 | State* self = (State *)cself; 149 | return self->perform(ins, outs, n); 150 | } 151 | 152 | /// Reset all parameters and stateful operators of a State object 153 | 154 | void reset(CommonState *cself) { 155 | State* self = (State *)cself; 156 | self->reset(cself->sr, cself->vs); 157 | } 158 | 159 | /// Set a parameter of a State object 160 | 161 | void setparameter(CommonState *cself, long index, t_param value, void *ref) { 162 | State *self = (State *)cself; 163 | switch (index) { 164 | case 0: self->set_freq(value); break; 165 | case 1: self->set_q(value); break; 166 | 167 | default: break; 168 | } 169 | } 170 | 171 | /// Get the value of a parameter of a State object 172 | 173 | void getparameter(CommonState *cself, long index, t_param *value) { 174 | State *self = (State *)cself; 175 | switch (index) { 176 | case 0: *value = self->m_freq_1; break; 177 | case 1: *value = self->m_q_2; break; 178 | 179 | default: break; 180 | } 181 | } 182 | 183 | /// Get the name of a parameter of a State object 184 | 185 | const char *getparametername(CommonState *cself, long index) { 186 | if (index >= 0 && index < cself->numparams) { 187 | return cself->params[index].name; 188 | } 189 | return 0; 190 | } 191 | 192 | /// Get the minimum value of a parameter of a State object 193 | 194 | t_param getparametermin(CommonState *cself, long index) { 195 | if (index >= 0 && index < cself->numparams) { 196 | return cself->params[index].outputmin; 197 | } 198 | return 0; 199 | } 200 | 201 | /// Get the maximum value of a parameter of a State object 202 | 203 | t_param getparametermax(CommonState *cself, long index) { 204 | if (index >= 0 && index < cself->numparams) { 205 | return cself->params[index].outputmax; 206 | } 207 | return 0; 208 | } 209 | 210 | /// Get parameter of a State object has a minimum and maximum value 211 | 212 | char getparameterhasminmax(CommonState *cself, long index) { 213 | if (index >= 0 && index < cself->numparams) { 214 | return cself->params[index].hasminmax; 215 | } 216 | return 0; 217 | } 218 | 219 | /// Get the units of a parameter of a State object 220 | 221 | const char *getparameterunits(CommonState *cself, long index) { 222 | if (index >= 0 && index < cself->numparams) { 223 | return cself->params[index].units; 224 | } 225 | return 0; 226 | } 227 | 228 | /// Get the size of the state of all parameters of a State object 229 | 230 | size_t getstatesize(CommonState *cself) { 231 | return genlib_getstatesize(cself, &getparameter); 232 | } 233 | 234 | /// Get the state of all parameters of a State object 235 | 236 | short getstate(CommonState *cself, char *state) { 237 | return genlib_getstate(cself, state, &getparameter); 238 | } 239 | 240 | /// set the state of all parameters of a State object 241 | 242 | short setstate(CommonState *cself, const char *state) { 243 | return genlib_setstate(cself, state, &setparameter); 244 | } 245 | 246 | /// Allocate and configure a new State object and it's internal CommonState: 247 | 248 | void *create(t_param sr, long vs) { 249 | State *self = new State; 250 | self->reset(sr, vs); 251 | ParamInfo *pi; 252 | self->__commonstate.inputnames = gen_kernel_innames; 253 | self->__commonstate.outputnames = gen_kernel_outnames; 254 | self->__commonstate.numins = gen_kernel_numins; 255 | self->__commonstate.numouts = gen_kernel_numouts; 256 | self->__commonstate.sr = sr; 257 | self->__commonstate.vs = vs; 258 | self->__commonstate.params = (ParamInfo *)genlib_sysmem_newptr(2 * sizeof(ParamInfo)); 259 | self->__commonstate.numparams = 2; 260 | // initialize parameter 0 ("m_freq_1") 261 | pi = self->__commonstate.params + 0; 262 | pi->name = "freq"; 263 | pi->paramtype = GENLIB_PARAMTYPE_FLOAT; 264 | pi->defaultvalue = self->m_freq_1; 265 | pi->defaultref = 0; 266 | pi->hasinputminmax = false; 267 | pi->inputmin = 0; 268 | pi->inputmax = 1; 269 | pi->hasminmax = true; 270 | pi->outputmin = 32; 271 | pi->outputmax = 96; 272 | pi->exp = 0; 273 | pi->units = ""; // no units defined 274 | // initialize parameter 1 ("m_q_2") 275 | pi = self->__commonstate.params + 1; 276 | pi->name = "q"; 277 | pi->paramtype = GENLIB_PARAMTYPE_FLOAT; 278 | pi->defaultvalue = self->m_q_2; 279 | pi->defaultref = 0; 280 | pi->hasinputminmax = false; 281 | pi->inputmin = 0; 282 | pi->inputmax = 1; 283 | pi->hasminmax = true; 284 | pi->outputmin = 0; 285 | pi->outputmax = 1; 286 | pi->exp = 0; 287 | pi->units = ""; // no units defined 288 | 289 | return self; 290 | } 291 | 292 | /// Release all resources and memory used by a State object: 293 | 294 | void destroy(CommonState *cself) { 295 | State *self = (State *)cself; 296 | genlib_sysmem_freeptr(cself->params); 297 | 298 | delete self; 299 | } 300 | 301 | 302 | } // gen_exported:: 303 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 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 "RtAudioMidiHost.h" 25 | 26 | using namespace GenPi; 27 | 28 | int main(int argc, const char* argv[]) { 29 | Runner runner(argc, argv); 30 | 31 | if (!runner.setup()) { 32 | while (!runner.run()) { 33 | if (runner.configure()) break; 34 | } 35 | } 36 | return 0; 37 | } 38 | --------------------------------------------------------------------------------