├── .gitignore ├── README ├── gendy-ex1.pd ├── gendy-gui.pd ├── gendy~-help.pd ├── package.txt └── src ├── breakpoint.cpp ├── breakpoint.h ├── gendy_waveform.cpp ├── gendy_waveform.h ├── gendy~.cpp ├── gendy~.h ├── log.cpp ├── log.h ├── splines.cpp ├── splines.h ├── types.h ├── util.cpp └── util.h /.gitignore: -------------------------------------------------------------------------------- 1 | pd-linux/ 2 | *.swp 3 | tags 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | gendy~ for Pure Data and Max/MSP 2 | 3 | Author: Spencer Russell 4 | 5 | Gendy is an external for Pure Data and Max/MSP based on Iannis Xenakis' 6 | Dynamic Stochastic Synthesis. 7 | 8 | The library implementing DSS is decoupled from the Pure Data and Max/MSP 9 | external code, so it should be relatively easily embeddable in other projects. 10 | 11 | For an excellent explanation of DSS, see Sergio Luque's master's thesis: 12 | http://www.sergioluque.com/thesis.html 13 | 14 | One of the departures from cannonical DSS is the introduction of "target waveforms" 15 | that the breakpoints gravitate towards. Currently only sinusoidal and square waves 16 | are implemented, but implementing new waveforms is trivial, I just haven't done it 17 | yet. 18 | -------------------------------------------------------------------------------- /gendy-ex1.pd: -------------------------------------------------------------------------------- 1 | #N canvas 4 278 1369 435 10; 2 | #X obj 163 35 gendy-gui; 3 | #X obj 547 393 dac~; 4 | #X obj 674 275 *~ 0.3; 5 | #X obj 164 267 *~ 0.3; 6 | #X obj 673 32 gendy-gui; 7 | #X connect 0 0 3 0; 8 | #X connect 0 1 4 0; 9 | #X connect 2 0 1 1; 10 | #X connect 3 0 1 0; 11 | #X connect 4 0 2 0; 12 | -------------------------------------------------------------------------------- /gendy-gui.pd: -------------------------------------------------------------------------------- 1 | #N canvas 4 592 1369 398 10; 2 | #X obj 552 303 gendy~; 3 | #X obj 298 219 hsl 128 15 50 2000 1 0 \$0-freq \$0-freq_in Freq -2 4 | -8 0 10 -262144 -1 -1 3786 1; 5 | #X msg 527 153 h_pull \$1; 6 | #X msg 706 153 v_pull \$1; 7 | #X msg 618 154 h_step \$1; 8 | #X msg 804 153 v_step \$1; 9 | #X msg 981 152 breakpoints \$1; 10 | #X floatatom 64 229 5 0 0 2 Breakpoints #0-breakpoints_in #0-breakpoints 11 | ; 12 | #N canvas 4 49 1369 186 (subpatch) 0; 13 | #X array \$0-waveform 1000 float 2; 14 | #X coords 0 1 1000 -1 150 100 1; 15 | #X restore 288 69 graph; 16 | #X obj 527 126 r \$0-h_pull; 17 | #X obj 618 128 r \$0-h_step; 18 | #X obj 706 125 r \$0-v_pull; 19 | #X obj 804 126 r \$0-v_step; 20 | #X obj 899 127 r \$0-freq; 21 | #X obj 980 125 r \$0-breakpoints; 22 | #X obj 551 336 outlet~; 23 | #X obj 810 27 inlet; 24 | #X obj 767 338 outlet; 25 | #X msg 899 154 freq \$1; 26 | #X obj 489 25 loadbang; 27 | #X obj 489 51 f \$0; 28 | #X obj 321 172 tgl 15 0 \$0-display \$0-display_in Display 20 7 0 10 29 | -262144 -1 -1 1 1; 30 | #X obj 1113 85 r \$0-display; 31 | #N canvas 4 251 1369 378 input 0; 32 | #X obj 145 303 s \$0-h_pull_in; 33 | #X obj 266 303 s \$0-h_step_in; 34 | #X obj 394 298 s \$0-v_pull_in; 35 | #X obj 510 292 s \$0-v_step_in; 36 | #X obj 638 292 s \$0-freq_in; 37 | #X obj 752 290 s \$0-breakpoints_in; 38 | #X obj 900 294 s \$0-display_in; 39 | #X obj 515 17 inlet; 40 | #X obj 515 42 route h_pull h_step v_pull v_step freq breakpoints display 41 | ; 42 | #X obj 918 64 route flat square sine; 43 | #X msg 918 86 flat; 44 | #X msg 968 88 square; 45 | #X msg 1021 87 sine; 46 | #X obj 1040 287 s \$0-waveshape_in; 47 | #X obj 1085 167 loadbang; 48 | #X msg 212 271 0.1; 49 | #X msg 324 274 0.5; 50 | #X msg 444 271 0.5; 51 | #X msg 559 262 0.5; 52 | #X msg 681 259 100; 53 | #X msg 769 261 7; 54 | #X msg 922 268 1; 55 | #X msg 1062 256 sine; 56 | #X obj 928 243 delay 100; 57 | #X connect 7 0 8 0; 58 | #X connect 8 0 0 0; 59 | #X connect 8 1 1 0; 60 | #X connect 8 2 2 0; 61 | #X connect 8 3 3 0; 62 | #X connect 8 4 4 0; 63 | #X connect 8 5 5 0; 64 | #X connect 8 6 6 0; 65 | #X connect 8 7 9 0; 66 | #X connect 9 0 10 0; 67 | #X connect 9 1 11 0; 68 | #X connect 9 2 12 0; 69 | #X connect 10 0 13 0; 70 | #X connect 11 0 13 0; 71 | #X connect 12 0 13 0; 72 | #X connect 14 0 22 0; 73 | #X connect 14 0 20 0; 74 | #X connect 14 0 19 0; 75 | #X connect 14 0 18 0; 76 | #X connect 14 0 17 0; 77 | #X connect 14 0 16 0; 78 | #X connect 14 0 15 0; 79 | #X connect 14 0 23 0; 80 | #X connect 15 0 0 0; 81 | #X connect 16 0 1 0; 82 | #X connect 17 0 2 0; 83 | #X connect 18 0 3 0; 84 | #X connect 19 0 4 0; 85 | #X connect 20 0 5 0; 86 | #X connect 21 0 6 0; 87 | #X connect 22 0 13 0; 88 | #X connect 23 0 21 0; 89 | #X restore 810 49 pd input; 90 | #N canvas 0 691 1375 186 waveshape 0; 91 | #X obj 31 31 cnv 15 68 88 empty empty Waveshape 3 9 0 12 -233017 -66577 92 | 0; 93 | #X obj 39 55 tgl 15 0 \$0-square \$0-square_in Square 17 7 0 10 -262144 94 | -1 -1 0 1; 95 | #X obj 39 75 tgl 15 0 \$0-sine \$0-sine_in Sine 17 7 0 10 -262144 -1 96 | -1 1 1; 97 | #X obj 39 95 tgl 15 0 \$0-flat \$0-flat_in Flat 17 7 0 10 -262144 -1 98 | -1 0 1; 99 | #X obj 283 139 r \$0-square; 100 | #X obj 280 248 r \$0-sine; 101 | #X obj 553 248 s \$0-sine_in; 102 | #X obj 280 353 r \$0-flat; 103 | #X obj 557 352 s \$0-flat_in; 104 | #X obj 552 167 s \$0-square_in; 105 | #X obj 283 161 select 1; 106 | #X msg 283 184 0; 107 | #X obj 280 274 select 1; 108 | #X msg 280 297 0; 109 | #X obj 280 380 select 1; 110 | #X msg 280 403 0; 111 | #X msg 379 68 1; 112 | #X msg 431 68 1; 113 | #X msg 484 70 1; 114 | #X msg 238 465 flat; 115 | #X msg 129 361 sine; 116 | #X msg 60 294 square; 117 | #X obj 130 550 s \$0-waveshape; 118 | #X obj 379 16 r \$0-waveshape_in; 119 | #X obj 379 39 route flat sine square; 120 | #X connect 4 0 10 0; 121 | #X connect 5 0 12 0; 122 | #X connect 7 0 14 0; 123 | #X connect 10 0 11 0; 124 | #X connect 10 0 21 0; 125 | #X connect 11 0 6 0; 126 | #X connect 11 0 8 0; 127 | #X connect 12 0 13 0; 128 | #X connect 12 0 20 0; 129 | #X connect 13 0 9 0; 130 | #X connect 13 0 8 0; 131 | #X connect 14 0 15 0; 132 | #X connect 14 0 19 0; 133 | #X connect 15 0 9 0; 134 | #X connect 15 0 6 0; 135 | #X connect 16 0 8 0; 136 | #X connect 17 0 6 0; 137 | #X connect 18 0 9 0; 138 | #X connect 19 0 22 0; 139 | #X connect 20 0 22 0; 140 | #X connect 21 0 22 0; 141 | #X connect 23 0 24 0; 142 | #X connect 24 0 16 0; 143 | #X connect 24 1 17 0; 144 | #X connect 24 2 18 0; 145 | #X coords 0 -1 1 1 70 90 2 30 30; 146 | #X restore 210 69 pd waveshape; 147 | #X obj 1218 145 r \$0-waveshape; 148 | #N canvas 4 719 1369 271 sliders 0; 149 | #X obj 11 11 cnv 15 140 140 empty empty empty 20 12 0 14 -233017 -66577 150 | 0; 151 | #X obj 16 27 hsl 128 15 0.001 1 1 0 \$0-h_pull \$0-h_pull_in h_pull 152 | -2 -8 0 10 -262144 -1 -1 8467 1; 153 | #X obj 17 62 hsl 128 15 0 1 0 0 \$0-v_pull \$0-v_pull_in v_pull -2 154 | -8 0 10 -262144 -1 -1 6350 1; 155 | #X obj 19 98 hsl 128 15 0 1 0 0 \$0-h_step \$0-h_step_in h_step -2 156 | -8 0 10 -262144 -1 -1 6350 1; 157 | #X obj 18 133 hsl 128 15 0 1 0 0 \$0-v_step \$0-v_step_in v_step -2 158 | -8 0 10 -262144 -1 -1 6350 1; 159 | #X coords 0 -1 1 1 142 142 2 10 10; 160 | #X restore 60 69 pd sliders; 161 | #X msg 1113 145 redraw; 162 | #X msg 489 81 table \$1-waveform; 163 | #X obj 1113 123 metro 75; 164 | #X msg 1183 124 display \$1; 165 | #X connect 0 0 15 0; 166 | #X connect 2 0 0 0; 167 | #X connect 2 0 17 0; 168 | #X connect 3 0 0 0; 169 | #X connect 3 0 17 0; 170 | #X connect 4 0 0 0; 171 | #X connect 4 0 17 0; 172 | #X connect 5 0 0 0; 173 | #X connect 5 0 17 0; 174 | #X connect 6 0 0 0; 175 | #X connect 6 0 17 0; 176 | #X connect 9 0 2 0; 177 | #X connect 10 0 4 0; 178 | #X connect 11 0 3 0; 179 | #X connect 12 0 5 0; 180 | #X connect 13 0 18 0; 181 | #X connect 14 0 6 0; 182 | #X connect 16 0 23 0; 183 | #X connect 18 0 17 0; 184 | #X connect 18 0 0 0; 185 | #X connect 19 0 20 0; 186 | #X connect 20 0 28 0; 187 | #X connect 22 0 29 0; 188 | #X connect 22 0 30 0; 189 | #X connect 25 0 0 0; 190 | #X connect 25 0 17 0; 191 | #X connect 27 0 0 0; 192 | #X connect 27 0 17 0; 193 | #X connect 28 0 0 0; 194 | #X connect 29 0 27 0; 195 | #X connect 30 0 17 0; 196 | #X coords 0 -1 1 1 400 200 1 50 50; 197 | -------------------------------------------------------------------------------- /gendy~-help.pd: -------------------------------------------------------------------------------- 1 | #N canvas 374 166 999 740 10; 2 | #X obj 719 352 gendy~; 3 | #X msg 27 457 h_pull \$1; 4 | #X obj 707 406 dac~; 5 | #X obj 719 378 *~ 0.1; 6 | #X obj 30 438 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 7 | -1 -1 12700 1; 8 | #X obj 236 443 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 9 | -1 -1 12700 1; 10 | #X msg 233 462 v_pull \$1; 11 | #X obj 238 254 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 12 | -1 -1 9300 1; 13 | #X msg 235 273 v_step \$1; 14 | #X obj 29 255 hsl 128 15 0 1 0 0 empty empty empty -2 -8 0 10 -262144 15 | -1 -1 10600 1; 16 | #X msg 26 274 h_step \$1; 17 | #X obj 28 77 hsl 128 15 20 10000 1 0 empty empty empty -2 -8 0 10 -262144 18 | -1 -1 7300 1; 19 | #X msg 25 115 freq \$1; 20 | #X msg 239 123 breakpoints \$1; 21 | #N canvas 0 0 450 300 (subpatch) 0; 22 | #X array gendygraph 1024 float 2; 23 | #X coords 0 1 1023 -1 200 140 1; 24 | #X restore 686 146 graph; 25 | #X msg 449 487 redraw; 26 | #X msg 37 610 linear; 27 | #X msg 28 589 cubic; 28 | #X msg 250 627 sine; 29 | #X msg 263 648 square; 30 | #X msg 239 606 flat; 31 | #X obj 449 466 metro 75; 32 | #X obj 449 447 tgl 15 0 empty empty empty 17 7 0 10 -262144 -1 -1 1 33 | 1; 34 | #X floatatom 25 97 5 0 0 0 - - -; 35 | #X obj 25 137 s gendy_con; 36 | #X obj 26 295 s gendy_con; 37 | #X obj 235 294 s gendy_con; 38 | #X obj 27 478 s gendy_con; 39 | #X obj 233 483 s gendy_con; 40 | #X obj 448 190 s gendy_con; 41 | #X obj 449 508 s gendy_con; 42 | #X obj 239 671 s gendy_con; 43 | #X obj 28 632 s gendy_con; 44 | #X obj 719 326 r gendy_con; 45 | #X obj 448 145 loadbang; 46 | #X obj 239 145 s gendy_con; 47 | #X text 677 456 gendy~; 48 | #X text 676 481 A Dynamic Stochastic Synthesis external; 49 | #X text 22 21 freq N; 50 | #X text 22 43 Sets the average waveform; 51 | #X text 22 56 frequency to N; 52 | #X text 26 185 h_step N; 53 | #X text 26 208 Varies the horizontal; 54 | #X text 25 223 stepsize of the; 55 | #X text 26 236 breakpoints (0-1); 56 | #X text 233 219 stepsize of the; 57 | #X text 235 232 breakpoints (0-1); 58 | #X text 235 184 v_step N; 59 | #X text 235 207 Varies the vertical; 60 | #X text 24 345 h_pull N; 61 | #X text 24 368 Varies how strongly; 62 | #X text 24 392 pulled towards its; 63 | #X text 24 380 each breakpoint is; 64 | #X text 24 405 center point; 65 | #X text 25 417 horizontally; 66 | #X text 231 345 h_pull N; 67 | #X text 231 368 Varies how strongly; 68 | #X text 231 392 pulled towards its; 69 | #X text 231 380 each breakpoint is; 70 | #X text 231 405 center point; 71 | #X text 232 417 vertically; 72 | #X text 25 521 cubic \, linear; 73 | #X text 24 544 Sets the interpolation; 74 | #X text 25 556 method; 75 | #X text 231 527 flat \, sine \, square; 76 | #X text 230 550 Sets the waveshape; 77 | #X text 230 562 that the breakpoints; 78 | #X text 230 575 gravitate towards; 79 | #X text 236 27 breakpoints N; 80 | #X text 236 49 Sets the number of; 81 | #X text 236 62 breakpoints; 82 | #X text 445 81 table NAME; 83 | #X text 446 102 Selects a table to; 84 | #X text 446 114 display the waveform; 85 | #X text 446 339 redraw; 86 | #X text 447 361 Refreshes the waveform; 87 | #X text 446 374 display; 88 | #X obj 449 401 loadbang; 89 | #X msg 449 421 1; 90 | #X text 676 506 This synthesizer creates a waveform by; 91 | #X text 676 518 interpolating a series of breakpoints \,; 92 | #X text 676 531 each of which moves in a 2-dimensional; 93 | #X text 676 543 random walk; 94 | #X obj 239 83 hradio 15 1 0 10 empty empty empty 0 -8 0 10 -262144 95 | -1 -1 6; 96 | #X obj 239 102 + 1; 97 | #X msg 448 168 table gendygraph; 98 | #X connect 0 0 3 0; 99 | #X connect 1 0 27 0; 100 | #X connect 3 0 2 0; 101 | #X connect 3 0 2 1; 102 | #X connect 4 0 1 0; 103 | #X connect 5 0 6 0; 104 | #X connect 6 0 28 0; 105 | #X connect 7 0 8 0; 106 | #X connect 8 0 26 0; 107 | #X connect 9 0 10 0; 108 | #X connect 10 0 25 0; 109 | #X connect 11 0 23 0; 110 | #X connect 12 0 24 0; 111 | #X connect 13 0 35 0; 112 | #X connect 15 0 30 0; 113 | #X connect 16 0 32 0; 114 | #X connect 17 0 32 0; 115 | #X connect 18 0 31 0; 116 | #X connect 19 0 31 0; 117 | #X connect 20 0 31 0; 118 | #X connect 21 0 15 0; 119 | #X connect 22 0 21 0; 120 | #X connect 23 0 12 0; 121 | #X connect 33 0 0 0; 122 | #X connect 34 0 85 0; 123 | #X connect 77 0 78 0; 124 | #X connect 78 0 22 0; 125 | #X connect 83 0 84 0; 126 | #X connect 84 0 13 0; 127 | #X connect 85 0 29 0; 128 | -------------------------------------------------------------------------------- /package.txt: -------------------------------------------------------------------------------- 1 | # 2 | # this file contains info for the flext build system 3 | # 4 | NAME=gendy~ 5 | SRCDIR=src 6 | SRCS= breakpoint.cpp \ 7 | gendy~.cpp \ 8 | gendy_waveform.cpp \ 9 | log.cpp \ 10 | splines.cpp \ 11 | util.cpp 12 | 13 | HDRS= breakpoint.h \ 14 | gendy~.h \ 15 | gendy_waveform.h \ 16 | log.h \ 17 | splines.h \ 18 | util.h 19 | -------------------------------------------------------------------------------- /src/breakpoint.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #include "breakpoint.h" 31 | #include "log.h" 32 | #include 33 | #include "util.h" 34 | 35 | breakpoint::breakpoint() { 36 | print_log("gendy~: New breakpoint with default args", LOG_DEBUG); 37 | duration = 0; 38 | amplitude = 0; 39 | center_dur = 0; 40 | center_amp = 0; 41 | } 42 | 43 | breakpoint::breakpoint(gendydur_t duration, gendyamp_t amplitude) { 44 | print_log("gendy~: New breakpoint with duration %u", duration, LOG_DEBUG); 45 | print_log("gendy~: \t\t\tamplitude %f", amplitude, LOG_DEBUG); 46 | this->duration = duration; 47 | this->amplitude = amplitude; 48 | } 49 | 50 | breakpoint::breakpoint(gendydur_t duration, gendyamp_t amplitude, 51 | gendydur_t center_dur, gendyamp_t center_amp) { 52 | print_log("gendy~: New breakpoint with duration %u", duration, LOG_DEBUG); 53 | print_log("gendy~: \t\t\tamplitude %f", amplitude, LOG_DEBUG); 54 | print_log("gendy~: \t\t\tcenter_dur %u", center_dur, LOG_DEBUG); 55 | print_log("gendy~: \t\t\tcenter_amp %f", center_amp, LOG_DEBUG); 56 | this->duration = duration; 57 | this->amplitude = amplitude; 58 | this->center_dur = center_dur; 59 | this->center_amp = center_amp; 60 | } 61 | 62 | // elastic_move 63 | // 64 | // elastic_move sets a new position for the breakpoint. The breakpoint is 65 | // moved (vertically and horizontally) from its current position by a normal 66 | // distributed distance, the standard deviations of which are h_step and 67 | // v_step. 68 | // 69 | // the breakpoint is also pulled toward its center by the factors h_pull and 70 | // v_pull, with a 1 corresponding to immediately jumping to the center point 71 | // and 0 not pulling toward the center point at all. 72 | // 73 | // amplitudes out of the audio range [-1,1] are mirrored back in. 74 | // durations less than 2 samples are set to 2. 75 | // 76 | void breakpoint::elastic_move(gendydur_t h_step, gendyamp_t v_step, 77 | gendydur_t h_pull, gendyamp_t v_pull) { 78 | gendydur_t old_duration = duration; 79 | gendydur_t new_duration; 80 | gendyamp_t new_amplitude; 81 | 82 | new_duration = old_duration * 83 | pow(center_dur / old_duration,h_pull * h_step) * 84 | exp(gauss() *0.1 * h_step * (1.0-h_pull)); 85 | /*new_duration = old_duration + round((1.0 - h_pull) * h_step * gauss() + 86 | (h_pull * (center_dur - old_duration))); */ 87 | // set boundaries on new_duration 88 | if(new_duration < 2) 89 | new_duration = 2; 90 | 91 | new_amplitude = amplitude + v_step * 92 | (v_pull * (center_amp - amplitude) + 93 | (1.0 - v_pull) * gauss()); 94 | /*new_amplitude = amplitude + (1 - v_pull) * v_step * gauss() + 95 | v_pull * (center_amp - amplitude);*/ 96 | // set mirror boundaries on new_amplitude 97 | do { 98 | if(new_amplitude > 1) 99 | new_amplitude = 2 - new_amplitude; 100 | if(new_amplitude < -1) 101 | new_amplitude = -2 - new_amplitude; 102 | } while (new_amplitude < -1 || new_amplitude > 1); 103 | 104 | duration = new_duration; 105 | amplitude = new_amplitude; 106 | } 107 | 108 | void breakpoint::set_duration(gendydur_t new_duration) { 109 | duration = new_duration; 110 | } 111 | 112 | void breakpoint::set_amplitude(gendyamp_t new_amplitude) { 113 | amplitude = new_amplitude; 114 | } 115 | 116 | void breakpoint::set_position(gendydur_t new_duration, gendyamp_t new_amplitude) { 117 | //TODO: argument sanitization 118 | duration = new_duration; 119 | amplitude = new_amplitude; 120 | } 121 | 122 | void breakpoint::set_center_duration(gendydur_t new_duration) { 123 | center_dur = new_duration; 124 | } 125 | 126 | void breakpoint::set_center_amplitude(gendyamp_t new_amplitude) { 127 | center_amp = new_amplitude; 128 | } 129 | 130 | // set_center 131 | // accessor function to set the amplitude and duration of a breakpoint's 132 | // center position 133 | 134 | void breakpoint::set_center(gendydur_t new_duration, gendyamp_t new_amplitude) { 135 | //TODO: argument sanitization 136 | center_dur= new_duration; 137 | center_amp = new_amplitude; 138 | } 139 | 140 | gendydur_t breakpoint::get_duration() const { 141 | return duration; 142 | } 143 | 144 | gendyamp_t breakpoint::get_amplitude() const { 145 | return amplitude; 146 | } 147 | 148 | gendydur_t breakpoint::get_center_duration() const { 149 | return center_dur; 150 | } 151 | 152 | gendyamp_t breakpoint::get_center_amplitude() const { 153 | return center_amp; 154 | } 155 | -------------------------------------------------------------------------------- /src/breakpoint.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef BREAKPOINT_H 31 | #define BREAKPOINT_H 32 | 33 | #include "types.h" 34 | 35 | class breakpoint 36 | { 37 | // store current breakpoint location 38 | // duration is in samples 39 | gendyamp_t amplitude; 40 | gendydur_t duration; 41 | 42 | // store the center point the breakpoint gravitates to 43 | gendyamp_t center_amp; 44 | gendydur_t center_dur; 45 | 46 | public: 47 | breakpoint(); 48 | breakpoint(gendydur_t duration, gendyamp_t amplitude); 49 | breakpoint(gendydur_t duration, gendyamp_t amplitude, 50 | gendydur_t center_dur, gendyamp_t center_amp); 51 | void elastic_move(gendydur_t h_step, gendyamp_t v_step, 52 | gendydur_t h_pull, gendyamp_t v_pull); 53 | void set_duration(gendydur_t new_duration); 54 | void set_amplitude(gendyamp_t new_amplitude); 55 | void set_position(gendydur_t new_duration, gendyamp_t new_amplitude); 56 | void set_center_duration(gendydur_t new_duration); 57 | void set_center_amplitude(gendyamp_t new_amplitude); 58 | void set_center(gendydur_t new_duration, gendyamp_t new_amplitude); 59 | gendydur_t get_duration() const; 60 | gendyamp_t get_amplitude() const; 61 | gendydur_t get_center_duration() const; 62 | gendyamp_t get_center_amplitude() const; 63 | }; 64 | #endif /* BREAKPOINT_H */ 65 | -------------------------------------------------------------------------------- /src/gendy_waveform.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #include "gendy_waveform.h" 31 | #include "log.h" 32 | #include "splines.h" 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | using namespace std; 39 | 40 | // gendy_waveform class constructor with all default arguments 41 | gendy_waveform::gendy_waveform() { 42 | //initialize variables to defaults 43 | step_width = 0.1; 44 | step_height = 0.1; 45 | duration_pull = 0.7; 46 | amplitude_pull = 0.4; 47 | constrain_endpoints = true; 48 | 49 | // start with a single breakpoint that spans the whole wavelength 50 | breakpoint_list.push_front(breakpoint(147,0,147,0)); 51 | // and add an guard point to the end (for linear interpolation) 52 | breakpoint_list.push_back(breakpoint(147,0,147,0)); 53 | // no pre-guard points 54 | breakpoint_begin = breakpoint_list.begin(); 55 | breakpoint_current = breakpoint_list.begin(); 56 | // 1 end guard point, which acts as the end of the list of actual 57 | // breakpoints 58 | breakpoint_end = --breakpoint_list.end(); 59 | 60 | set_interpolation(CUBIC); 61 | 62 | // set the average wavelength for 300 Hz at 44.1 kHz 63 | set_avg_wavelength(147); 64 | waveshape = FLAT; 65 | phase = 0; 66 | 67 | 68 | set_num_breakpoints(8); 69 | reset_breakpoints(); 70 | move_breakpoints(); 71 | } 72 | 73 | gendy_waveform::~gendy_waveform() { 74 | } 75 | 76 | //TODO: protect against this getting called before data 77 | //strucutres are set up 78 | void gendy_waveform::set_num_breakpoints(int new_size) { 79 | if(new_size <= 0) { 80 | print_log("gendy~: Cannot resize to less than 1, resizing to 1", LOG_INFO); 81 | new_size = 1; 82 | } 83 | 84 | unsigned int target_length = new_size + get_num_guardpoints(); 85 | 86 | while(breakpoint_list.size() < (target_length)) 87 | add_breakpoint(); 88 | while(breakpoint_list.size() > (target_length)) 89 | remove_breakpoint(); 90 | center_breakpoints(); 91 | } 92 | 93 | void gendy_waveform::set_avg_wavelength(float new_wavelength) { 94 | average_wavelength = new_wavelength; 95 | center_breakpoints(); 96 | } 97 | 98 | 99 | unsigned int gendy_waveform::get_num_guardpoints() const { 100 | return breakpoint_list.size() - get_num_breakpoints(); 101 | } 102 | 103 | unsigned int gendy_waveform::get_num_breakpoints() const { 104 | list::const_iterator i = breakpoint_begin; 105 | unsigned int num_breakpoints = 0; 106 | while(i != breakpoint_end) { 107 | ++i; 108 | ++num_breakpoints; 109 | } 110 | return num_breakpoints; 111 | } 112 | 113 | void gendy_waveform::set_pre_guardpoints(unsigned int guardpoints) { 114 | list::iterator src = breakpoint_end; 115 | list::iterator i = breakpoint_begin; 116 | //work backwards from the first breakpoint until: 117 | // a) we get to the beginning of the list (more guard points needed) 118 | // b) guardpoints goes to 0 (we need to remove guardpoints) 119 | // c) both (we have the proper number of guardpoints) 120 | //we keep track of src because that's where we'll start copying 121 | //guard points from 122 | while(guardpoints && i != breakpoint_list.begin()) { 123 | --guardpoints; 124 | --i; 125 | --src; 126 | } 127 | //if we're not at the beginning of the list yet, delete guard points 128 | while(i != breakpoint_list.begin()) 129 | breakpoint_list.pop_front(); 130 | //if guardpoints hasn't run out yet, we need some more. copy them. 131 | while(guardpoints--) 132 | breakpoint_list.push_front(*(src--)); 133 | } 134 | 135 | void gendy_waveform::set_post_guardpoints(unsigned int guardpoints) { 136 | list::iterator src = breakpoint_begin; 137 | // move breakpoint_end to point at the last breakpoint instead 138 | // of the first node after the last breakpoint, so it doesn't 139 | // get clobbered 140 | --breakpoint_end; 141 | list::iterator i = breakpoint_end; 142 | //work forwards from the last breakpoint until: 143 | // a) we get to the end of the list (more guard points needed) 144 | // b) guardpoints goes to 0 (we need to remove guardpoints) 145 | // c) both (we have the proper number of guardpoints) 146 | //we keep track of src because that's where we'll start copying 147 | //guard points from 148 | while(guardpoints && i != --breakpoint_list.end()) { 149 | --guardpoints; 150 | ++i; 151 | ++src; 152 | } 153 | //if we're not at the beginning of the list yet, delete guard points 154 | while(i != --breakpoint_list.end()) 155 | breakpoint_list.pop_back(); 156 | //if guardpoints hasn't run out yet, we need some more. copy them. 157 | while(guardpoints--) 158 | breakpoint_list.push_back(*(src++)); 159 | //now we put breakpoint_end back where it's supposed to be 160 | ++breakpoint_end; 161 | } 162 | 163 | void gendy_waveform::set_interpolation(interpolation_t new_interpolation) { 164 | if(new_interpolation == LINEAR) { 165 | interpolation_type = LINEAR; 166 | set_pre_guardpoints(0); 167 | set_post_guardpoints(1); 168 | } 169 | else if(new_interpolation == CUBIC) { 170 | interpolation_type = CUBIC; 171 | set_pre_guardpoints(1); 172 | set_post_guardpoints(2); 173 | } 174 | else { 175 | print_log("gendy~: unimplemented interpolation. defaulting to linear", 176 | LOG_ERROR); 177 | } 178 | } 179 | 180 | /* 181 | void gendy_waveform::set_interpolation_type(t_symbol *new_interpolation) { 182 | if(strcmp(GetString(new_interpolation), "linear") == 0) 183 | interpolation_type = LINEAR; 184 | else 185 | post("So far only linear interpolation implemented."); 186 | } */ 187 | 188 | void gendy_waveform::set_waveshape(waveshape_t new_waveshape) { 189 | waveshape = new_waveshape; 190 | center_breakpoints(); 191 | } 192 | 193 | void gendy_waveform::set_step_width(float new_width) { 194 | step_width = new_width; 195 | } 196 | 197 | void gendy_waveform::set_step_height(float new_height) { 198 | step_height = new_height; 199 | } 200 | 201 | void gendy_waveform::set_duration_pull(float new_pull) { 202 | duration_pull = new_pull; 203 | } 204 | 205 | void gendy_waveform::set_amplitude_pull(float new_pull) { 206 | amplitude_pull = new_pull; 207 | } 208 | 209 | void gendy_waveform::set_constrain_endpoints(bool constrain) { 210 | constrain_endpoints = constrain; 211 | } 212 | 213 | float gendy_waveform::get_wavelength() const { 214 | list::iterator i; 215 | float wavelength = 0; 216 | for(i = breakpoint_begin; i != breakpoint_end; i++) 217 | wavelength += i->get_duration(); 218 | return wavelength; 219 | } 220 | 221 | // set new positions for all the breakpoints 222 | void gendy_waveform::move_breakpoints() { 223 | int breakpoint_count; 224 | 225 | // first we copy the last breakpoints of the current cycle into 226 | // the pre guard points, which represent the past 227 | 228 | list::iterator i = breakpoint_begin; 229 | list::iterator j = breakpoint_end; 230 | while(i != breakpoint_list.begin()) 231 | *(--i) = *(--j); 232 | 233 | // now we copy the post guard points (which represent the first 234 | // breakpoints of the next cycle) into the beginning of this cycle 235 | i = breakpoint_begin; 236 | j = breakpoint_end; 237 | while(j != breakpoint_list.end()) 238 | *(i++) = *(j++); 239 | // i now points to the first breakpoint that needs to be newly calculated. 240 | // we'll also continue into the post guard points and recalculate those, 241 | // they are the future 242 | 243 | 244 | // calculate new values for all the rest of the breakpoints 245 | while(i != breakpoint_list.end()) { 246 | i->elastic_move(step_width, step_height, duration_pull, amplitude_pull); 247 | i++; 248 | } 249 | } 250 | 251 | // adds a breakpoint by splitting the longest breakpoint into two 252 | void gendy_waveform::add_breakpoint() { 253 | gendydur_t new_duration; 254 | gendyamp_t new_amplitude; 255 | 256 | gendydur_t longest_dur = 0; 257 | list::iterator longest_dur_breakpoint; 258 | list::iterator breakpoint_iter; 259 | 260 | // find the longest breakpoint 261 | for(breakpoint_iter = breakpoint_begin; 262 | breakpoint_iter != breakpoint_end; 263 | breakpoint_iter++) { 264 | if((breakpoint_iter->get_duration()) > longest_dur) { 265 | longest_dur = breakpoint_iter->get_duration(); 266 | longest_dur_breakpoint = breakpoint_iter; 267 | } 268 | } 269 | 270 | // set the duration of the new breakpoint to be half the previous 271 | new_duration = longest_dur_breakpoint->get_duration() / 2; 272 | // halve the duration of the previous breakpoint 273 | longest_dur_breakpoint->set_duration(new_duration); 274 | // set the new amplitude to be the average of the 2 adjacent breakpoints 275 | // and move longest_dur_breakpoint iterator to the next breakpoint 276 | // for insertion 277 | new_amplitude = (longest_dur_breakpoint->get_amplitude() + 278 | (++longest_dur_breakpoint)->get_amplitude()) / 2; 279 | // insert the breakpoint in the list 280 | breakpoint_list.insert(longest_dur_breakpoint, 281 | breakpoint(new_duration, new_amplitude)); 282 | //TODO: copy data to guard points if need be 283 | } 284 | 285 | // remove the breakpoint closest to its neighbors. breakpoints centers 286 | // should be reset after. 287 | void gendy_waveform::remove_breakpoint() { 288 | // start smallest_space to be the largest it can be 289 | gendydur_t smallest_space = numeric_limits::max(); 290 | gendydur_t space; 291 | list::iterator smallest_space_position = breakpoint_list.end(); 292 | 293 | // find the breakpoint closest to the adjacent breakpoints 294 | list::iterator breakpoint_iter = breakpoint_begin; 295 | list::iterator breakpoint_last = breakpoint_end; 296 | --breakpoint_last; 297 | while(breakpoint_iter != breakpoint_last) { 298 | space = breakpoint_iter->get_duration() + 299 | (++breakpoint_iter)->get_duration(); 300 | if(space < smallest_space) { 301 | smallest_space = space; 302 | smallest_space_position = breakpoint_iter; 303 | } 304 | } 305 | if(smallest_space_position != breakpoint_list.end()) { 306 | // if the element we're about to erase is the current one 307 | if(breakpoint_current == smallest_space_position) { 308 | --breakpoint_current; 309 | phase += breakpoint_current->get_duration(); 310 | } 311 | // erase returns the list element following the erased one 312 | smallest_space_position = breakpoint_list.erase(smallest_space_position); 313 | // add the erased breakpoint's duration to the previous breakpoint 314 | (--smallest_space_position)->set_duration(smallest_space); 315 | //TODO: update guard points if need be 316 | } 317 | } 318 | 319 | // center_breakpoints() calculates center positions for all the breakpoints 320 | // TODO: sawtooth and triangle 321 | // TODO: crashes when called on empty breakpoint list 322 | void gendy_waveform::center_breakpoints() { 323 | gendydur_t new_dur; 324 | gendyamp_t new_amp; 325 | 326 | list::iterator breakpoint_iter = breakpoint_begin; 327 | unsigned int breakpoint_index = 0; 328 | unsigned int num_breakpoints = get_num_breakpoints(); 329 | while(breakpoint_iter != breakpoint_end) { 330 | // evenly distribute the breakpoints along the waveform 331 | breakpoint_iter->set_center_duration(average_wavelength / num_breakpoints); 332 | 333 | float t = (breakpoint_index) / (float)num_breakpoints; 334 | if(waveshape == FLAT) 335 | breakpoint_iter->set_center_amplitude(0); 336 | else if(waveshape == SINE) 337 | breakpoint_iter->set_center_amplitude(sin(2 * M_PI * t)); 338 | else if(waveshape == SQUARE) 339 | breakpoint_iter->set_center_amplitude(t < 0.5 ? 1 : -1); 340 | breakpoint_iter++; 341 | breakpoint_index++; 342 | } 343 | 344 | // copy center data starting at the end of the actual breakpoints 345 | // into the beginning guard points 346 | list::iterator i = breakpoint_begin; 347 | list::iterator j = breakpoint_end; 348 | while(i != breakpoint_list.begin()) 349 | *(--i) = *(--j); 350 | 351 | // copy center data starting at the beginning of the actual breakpoints 352 | // into the end guard points 353 | i = breakpoint_begin; 354 | j = breakpoint_end; 355 | while(j != breakpoint_list.end()) 356 | *(j++) = *(i++); 357 | } 358 | 359 | // reset_breakpoints() sets all of the breakpoint positions to be the 360 | // center positions 361 | void gendy_waveform::reset_breakpoints() { 362 | list::iterator current; 363 | for(current = breakpoint_list.begin(); 364 | current != breakpoint_list.end(); current++) 365 | current->set_position(current->get_center_duration(), 366 | current->get_center_amplitude()); 367 | } 368 | 369 | 370 | /* 371 | * generates a block of gendy audio. 372 | * This function will take care of moving the breakpoints when it reaches 373 | * the end of a cycle. 374 | */ 375 | //TODO: should this really return the number of samples copied? it's always 376 | // bufsize 377 | unsigned int gendy_waveform::get_block(gendysamp_t *dest, unsigned int bufsize) { 378 | if(interpolation_type == LINEAR) { 379 | // assert that we have no pre guard points and at least 1 post guard point 380 | assert(breakpoint_begin == breakpoint_list.begin()); 381 | assert(breakpoint_end != breakpoint_list.end()); 382 | // generate the endpoints for the current segment 383 | list::iterator breakpoint_next = breakpoint_current; 384 | breakpoint_next++; 385 | gendydur_t current_dur = breakpoint_current->get_duration(); 386 | gendydur_t current_amp = breakpoint_current->get_amplitude(); 387 | gendydur_t next_dur = breakpoint_next->get_duration(); 388 | gendydur_t next_amp = breakpoint_next->get_amplitude(); 389 | 390 | for(unsigned int i = 0; i < bufsize; i++) { 391 | dest[i] = current_amp + phase / current_dur * (next_amp - current_amp); 392 | phase++; 393 | // if we've reached the end of the current segment 394 | if(phase > current_dur) { 395 | breakpoint_current = breakpoint_next;; 396 | breakpoint_next++; 397 | phase -= current_dur; 398 | current_dur = next_dur; 399 | current_amp = next_amp; 400 | // if we've reached the end of this cycle 401 | if(breakpoint_next == breakpoint_end) { 402 | move_breakpoints(); 403 | // wrap around the current and next iterators to the beginning 404 | breakpoint_current = breakpoint_begin; 405 | breakpoint_next = breakpoint_begin; 406 | breakpoint_next++; 407 | } 408 | next_dur = breakpoint_next->get_duration(); 409 | next_amp = breakpoint_next->get_amplitude(); 410 | } 411 | } 412 | } 413 | else if(interpolation_type == CUBIC) { 414 | double x[4]; 415 | double y[4]; 416 | double coefs[4]; 417 | // set iter to be the breakpoint before the current one 418 | list::const_iterator iter = breakpoint_current; 419 | --iter; 420 | //collect the 4 points needed to interpolate in the first segment 421 | //x[0] will be negative enough to make x[1]=0, the beginning of 422 | //the segment we're actually interested in here 423 | x[0] = -iter->get_duration(); 424 | y[0] = iter->get_amplitude(); 425 | for(int i = 1; i < 4; i++) { 426 | x[i] = x[i-1] + iter->get_duration(); 427 | ++iter; 428 | y[i] = iter->get_amplitude(); 429 | } 430 | //iter is now pointing at the 4th point of this set 431 | 432 | get_cspline_coefs(x,y,coefs); 433 | 434 | for(unsigned int i = 0; i < bufsize; i++) { 435 | dest[i] = cspline_interp(coefs,phase); 436 | ++phase; 437 | //if we're past the end of the segment 438 | if(phase > x[2]) { 439 | ++breakpoint_current; 440 | phase -= x[2]; 441 | // if we've reached the end of the current cycle 442 | if(breakpoint_current == breakpoint_end) { 443 | move_breakpoints(); 444 | breakpoint_current = breakpoint_begin; 445 | } 446 | iter = breakpoint_current; 447 | --iter; 448 | x[0] = -iter->get_duration(); 449 | y[0] = iter->get_amplitude(); 450 | for(int i = 1; i < 4; i++) { 451 | x[i] = x[i-1] + iter->get_duration(); 452 | ++iter; 453 | y[i] = iter->get_amplitude(); 454 | } 455 | get_cspline_coefs(x,y,coefs); 456 | } 457 | } 458 | } 459 | else { 460 | print_log("gendy~: Unimplemeted Interpolation Type", LOG_ERROR); 461 | assert(0); 462 | } 463 | return bufsize; 464 | } 465 | 466 | //TODO:needs protection against buffer overrun 467 | unsigned int gendy_waveform::get_cycle(gendysamp_t *dest, unsigned int bufsize) const { 468 | if(interpolation_type == LINEAR) { 469 | assert(get_num_guardpoints() == 1); 470 | 471 | // we'll be going through the waveform piecewise. next stores 472 | // the endpoint of the current section 473 | list::const_iterator next = breakpoint_list.begin(); 474 | // keep track of how long before a sample boundry the current 475 | // segment started. the first segment will start at the beginning of the buffer 476 | gendydur_t segment_shift = 0; 477 | gendydur_t current_dur, next_dur; 478 | gendyamp_t current_amp, next_amp; 479 | double slope; 480 | current_dur = next->get_duration(); 481 | current_amp = next->get_amplitude(); 482 | 483 | unsigned int buffer_offset = 0; 484 | // for each breakpoint 485 | while(++next != breakpoint_list.end()) { 486 | next_amp = next->get_amplitude(); 487 | slope = (next_amp - current_amp) / current_dur; 488 | unsigned int i = 0; 489 | while(i + segment_shift < current_dur && i + buffer_offset < bufsize) { 490 | dest[i + buffer_offset] = current_amp + 491 | slope * (i + segment_shift); 492 | i++; 493 | } 494 | buffer_offset += i; 495 | segment_shift = (gendydur_t)i + segment_shift - current_dur; 496 | current_dur = next->get_duration(); 497 | current_amp = next_amp; 498 | } 499 | return buffer_offset; 500 | } 501 | else if(interpolation_type == CUBIC) { 502 | assert(get_num_guardpoints() == 3); 503 | double x[4]; 504 | double y[4]; 505 | double coefs[4]; 506 | double x_in = 0; 507 | // set iter to be the first guard breakpoint 508 | list::const_iterator iter = breakpoint_begin; 509 | --iter; 510 | //collect the 4 points needed to interpolate in the first segment 511 | //x[0] will be negative enough to make x[1]=0, the beginning of 512 | //the segment we're actually interested in here 513 | x[0] = -iter->get_duration(); 514 | y[0] = iter->get_amplitude(); 515 | for(int i = 1; i < 4; i++) { 516 | x[i] = x[i-1] + iter->get_duration(); 517 | ++iter; 518 | y[i] = iter->get_amplitude(); 519 | } 520 | //iter is now pointing at the 4th point of this set 521 | 522 | get_cspline_coefs(x,y,coefs); 523 | 524 | unsigned int i = 0; 525 | for(i = 0; i < bufsize && iter != breakpoint_list.end(); i++) { 526 | dest[i] = cspline_interp(coefs,x_in); 527 | ++x_in; 528 | //if we're past the end of the segment 529 | if(x_in > x[2]) { 530 | x_in -= x[2]; 531 | for(int j = 0; j < 3; ++j) { 532 | x[j] = x[j+1] - x[2]; 533 | y[j] = y[j+1]; 534 | } 535 | x[3] = x[2] + iter->get_duration(); 536 | if(++iter != breakpoint_list.end()) { 537 | y[3] = iter->get_amplitude(); 538 | get_cspline_coefs(x,y,coefs); 539 | } 540 | } 541 | } 542 | return i; 543 | } 544 | } 545 | -------------------------------------------------------------------------------- /src/gendy_waveform.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef GENDY_WAVEFORM_H 31 | #define GENDY_WAVEFORM_H 32 | 33 | #include "types.h" 34 | #include "breakpoint.h" 35 | #include 36 | 37 | class gendy_waveform 38 | { 39 | // keep track of where we are in the current segment(in samples) 40 | gendydur_t phase; 41 | // average wavelength in samples. 42 | float average_wavelength; 43 | // list of breakpoints plus guard points(for continuity) 44 | std::list breakpoint_list; 45 | // the first breakpoint after the guard points 46 | std::list::iterator breakpoint_begin; 47 | // the first guard point after the breakpoints 48 | std::list::iterator breakpoint_end; 49 | // the current breakpoint that the next request block will start with 50 | std::list::iterator breakpoint_current;; 51 | // set the type of interpolation(see defines at top) 52 | interpolation_t interpolation_type; 53 | // the waveshape that the breakpoints will gravitate to 54 | waveshape_t waveshape; 55 | // constrain endpoints to 0 56 | bool constrain_endpoints; 57 | // determines the motion of the breakpoints. expected to be 0-1, where 58 | // 0 is no motion and 1 is basically fully random jumps 59 | float step_width; 60 | float step_height; 61 | // the extent to which the duration and amplitude are pulled to match 62 | // the waveshape. ranges from 0 to 1 63 | float duration_pull; 64 | float amplitude_pull; 65 | // eventually debugging info will be switchable on an object-basis 66 | bool debug; 67 | 68 | void move_breakpoints(); 69 | void generate_from_breakpoints(); 70 | void add_breakpoint(); 71 | void remove_breakpoint(); 72 | void center_breakpoints(); 73 | void reset_breakpoints(); 74 | void set_pre_guardpoints(unsigned int guardpoints); 75 | void set_post_guardpoints(unsigned int guardpoints); 76 | 77 | public: 78 | gendy_waveform(); 79 | ~gendy_waveform(); 80 | //gendy_waveform(float freq); 81 | void set_num_breakpoints(int new_size); 82 | void set_avg_wavelength(float new_wavelength); 83 | void set_interpolation(interpolation_t new_interpolation); 84 | void set_waveshape(waveshape_t new_waveshape); 85 | void set_step_width(float new_width); 86 | void set_step_height(float new_height); 87 | void set_amplitude_pull(float new_pull); 88 | void set_duration_pull(float new_pull); 89 | void set_constrain_endpoints(bool constrain); 90 | float get_wavelength() const; 91 | unsigned int get_num_breakpoints() const; 92 | unsigned int get_num_guardpoints() const; 93 | unsigned int get_block(gendysamp_t *dest, unsigned int bufsize); 94 | unsigned int get_cycle(gendysamp_t *dest, unsigned int bufsize) const; 95 | }; //end gendy_waveform class def 96 | 97 | #endif /* GENDY_WAVEFORM_H */ 98 | -------------------------------------------------------------------------------- /src/gendy~.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | // gendy~ - an implementation of Iannis Xenakis' Dynamic 31 | // Stochastic Synthesis as an object for Pure Data. 32 | // 33 | // This project uses Thomas Grill's Flext framework, which 34 | // is necessary to compile and run it. 35 | // 36 | 37 | #include 38 | #include 39 | #include "gendy~.h" 40 | #include "log.h" 41 | 42 | using namespace std; 43 | 44 | #if !defined(FLEXT_VERSION) || (FLEXT_VERSION < 502) 45 | #error You need at least flext version 0.5.2 46 | #endif 47 | 48 | 49 | // object class constructor(run at each gendy object creation) 50 | gendy::gendy() { 51 | id = gendy_count; 52 | gendy_count++; 53 | if(debug) 54 | print_log("gendy~ #%d: Constructor initiated", id, LOG_DEBUG); 55 | AddInAnything("control input"); // control input 56 | AddOutSignal("audio out"); // audio output 57 | 58 | display_buf = NULL; 59 | 60 | if(debug) 61 | print_log("gendy~ #%d: Constructor terminated", id, LOG_DEBUG); 62 | } 63 | 64 | gendy::~gendy() { 65 | if(debug) 66 | print_log("gendy~ #%d: Destructor initiated", id, LOG_DEBUG); 67 | gendy_count--; 68 | if(debug) 69 | print_log("gendy~ #%d: Destructor terminated", id, LOG_DEBUG); 70 | } 71 | 72 | void gendy::class_setup(t_classid thisclass) { 73 | // associate methods with incoming messages on inlet 0 74 | print_log("Class constructor beginning", LOG_DEBUG); 75 | FLEXT_CADDMETHOD_(thisclass, 0, "freq", set_frequency); 76 | FLEXT_CADDMETHOD_(thisclass, 0, "breakpoints", set_num_breakpoints); 77 | FLEXT_CADDMETHOD_(thisclass, 0, "h_step", set_h_step); 78 | FLEXT_CADDMETHOD_(thisclass, 0, "v_step", set_v_step); 79 | FLEXT_CADDMETHOD_(thisclass, 0, "h_pull", set_h_pull); 80 | FLEXT_CADDMETHOD_(thisclass, 0, "v_pull", set_v_pull); 81 | FLEXT_CADDMETHOD_(thisclass, 0, "linear", set_interpolation_lin); 82 | FLEXT_CADDMETHOD_(thisclass, 0, "cubic", set_interpolation_cubic); 83 | FLEXT_CADDMETHOD_(thisclass, 0, "spline", set_interpolation_spline); 84 | FLEXT_CADDMETHOD_(thisclass, 0, "sinc", set_interpolation_sinc); 85 | FLEXT_CADDMETHOD_(thisclass, 0, "flat", set_waveform_flat); 86 | FLEXT_CADDMETHOD_(thisclass, 0, "sine", set_waveform_sine); 87 | FLEXT_CADDMETHOD_(thisclass, 0, "square", set_waveform_square); 88 | FLEXT_CADDMETHOD_(thisclass, 0, "debug", set_debug); 89 | FLEXT_CADDMETHOD_(thisclass, 0, "table", set_outbuf); 90 | FLEXT_CADDMETHOD_(thisclass, 0, "redraw", redraw); 91 | print_log("",LOG_INFO); 92 | print_log("-- gendy~ v%d.%d.%d by Spencer Russell --", 93 | GENDY_MAJ, GENDY_MIN, GENDY_REV, LOG_INFO); 94 | print_log("gendy~: please report bugs to https://github.com/ssfrr/gendyflext/issues", LOG_INFO); 95 | print_log("Class constructor ending", LOG_DEBUG); 96 | } 97 | 98 | // Now we define our DSP function. It gets these arguments: 99 | // 100 | // n: length of signal vector. 101 | // float *const *in, float *const *out: 102 | // These are arrays of signal vectors(in is a pointer to const pointer to float) 103 | 104 | void gendy::m_signal(int n, float *const *in, float *const *out) { 105 | waveform.get_block(out[0], n); 106 | } 107 | 108 | // Message handling functions 109 | 110 | void gendy::set_frequency(float new_freq) { 111 | print_log("set_frequency(%f)", new_freq, LOG_DEBUG); 112 | waveform.set_avg_wavelength(Samplerate() / new_freq); 113 | } 114 | 115 | void gendy::set_num_breakpoints(float num_breakpoints) { 116 | print_log("set_num_breakpoints(%f)", num_breakpoints, LOG_DEBUG); 117 | waveform.set_num_breakpoints(num_breakpoints); 118 | } 119 | 120 | void gendy::set_h_step(float new_stepsize) { 121 | print_log("set_h_step(%f)", new_stepsize, LOG_DEBUG); 122 | waveform.set_step_width(new_stepsize); 123 | } 124 | 125 | void gendy::set_v_step(float new_stepsize) { 126 | print_log("set_v_step(%f)", new_stepsize, LOG_DEBUG); 127 | waveform.set_step_height(new_stepsize); 128 | } 129 | 130 | void gendy::set_h_pull(float new_pull) { 131 | print_log("set_h_pull(%f)", new_pull, LOG_DEBUG); 132 | waveform.set_duration_pull(new_pull); 133 | } 134 | 135 | void gendy::set_v_pull(float new_pull) { 136 | print_log("set_v_pull(%f)", new_pull, LOG_DEBUG); 137 | waveform.set_amplitude_pull(new_pull); 138 | } 139 | 140 | void gendy::set_interpolation_lin() { 141 | print_log("set_interpolation_lin()", LOG_DEBUG); 142 | set_interpolation(LINEAR); 143 | } 144 | 145 | void gendy::set_interpolation_cubic() { 146 | print_log("set_interpolation_cubic()", LOG_DEBUG); 147 | set_interpolation(CUBIC); 148 | } 149 | 150 | void gendy::set_interpolation_spline() { 151 | print_log("set_interpolation_spline()", LOG_DEBUG); 152 | set_interpolation(SPLINE); 153 | } 154 | 155 | void gendy::set_interpolation_sinc() { 156 | print_log("set_interpolation_sinc()", LOG_DEBUG); 157 | set_interpolation(SINC); 158 | } 159 | 160 | void gendy::set_waveform_flat() { 161 | print_log("set_waveform_flat()", LOG_DEBUG); 162 | set_waveform(FLAT); 163 | } 164 | 165 | void gendy::set_waveform_sine() { 166 | print_log("set_waveform_sine()", LOG_DEBUG); 167 | set_waveform(SINE); 168 | } 169 | 170 | void gendy::set_waveform_square() { 171 | print_log("set_waveform_square()", LOG_DEBUG); 172 | set_waveform(SQUARE); 173 | } 174 | 175 | void gendy::set_debug(int new_debug) { 176 | print_log("set_debug(%d)", new_debug, LOG_DEBUG); 177 | if(new_debug) 178 | debug = true; 179 | else 180 | debug = false; 181 | } 182 | 183 | // TODO let flext take care of buffer setting argument checking? 184 | 185 | void gendy::set_outbuf(short argc, t_atom *argv) { 186 | if(argc == 0) 187 | // no argument toggles waveform display 188 | print_log("gendy~: missing buffer name", LOG_ERROR); 189 | else if(argc == 1) { 190 | if(IsFloat(argv[0])) 191 | print_log("gendy~: invalid buffer name", LOG_ERROR); 192 | else if(IsSymbol(argv[0])) { 193 | // symbol argument, set output buffer 194 | // TODO: better error reporting 195 | // delete existing buffer reference 196 | if(display_buf) { 197 | delete display_buf; 198 | } 199 | display_buf = new buffer(GetSymbol(argv[0])); 200 | if(!display_buf->Ok()) { 201 | print_log("gendy~: buffer not valid", LOG_ERROR); 202 | delete display_buf; 203 | display_buf = NULL; 204 | } 205 | } 206 | } 207 | } 208 | 209 | // private class methods 210 | void gendy::set_interpolation(interpolation_t new_interpolation) { 211 | waveform.set_interpolation(new_interpolation); 212 | } 213 | 214 | void gendy::set_waveform(waveshape_t new_waveform) { 215 | waveform.set_waveshape(new_waveform); 216 | } 217 | 218 | void gendy::redraw() { 219 | int n = 0; 220 | gendysamp_t *temp_buf; 221 | 222 | if(!display_buf || !display_buf->Ok()) { 223 | print_log("gendy~: Invalid Buffer", LOG_ERROR); 224 | return; 225 | } 226 | 227 | //TODO: is there a way to do this without the temp buffer? 228 | flext::buffer::lock_t state = display_buf->Lock(); 229 | display_buf->Update(); 230 | // resize table to fit 1 wavelength 231 | //display_buf->Frames(current_wavelength, false, false); 232 | int bufsize = display_buf->Frames(); 233 | temp_buf = new gendysamp_t[bufsize]; 234 | //TODO: this is not threadsafe. wavelength could change. 235 | int wavelength = waveform.get_wavelength(); 236 | waveform.get_cycle(temp_buf, bufsize); 237 | // here we copy from the raw float array to the flext buffer object 238 | for(; n < wavelength && n < bufsize; ++n) 239 | (*display_buf)[n] = temp_buf[n]; 240 | delete temp_buf; 241 | // zero out the rest of the buffer 242 | while(n < bufsize) 243 | (*display_buf)[n++]= 0; 244 | display_buf->Dirty(true); 245 | display_buf->Unlock(state); 246 | } 247 | 248 | //register the gendy class as a PD or Max object 249 | FLEXT_NEW_DSP("gendy~", gendy) 250 | -------------------------------------------------------------------------------- /src/gendy~.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | // gendy~ - an implementation of Iannis Xenakis' Dynamic 31 | // Stochastic Synthesis as an object for Pure Data. 32 | // 33 | // This project uses Thomas Grill's Flext framework, which 34 | // is necessary to compile and run it. 35 | 36 | #ifndef GENDY_H 37 | #define GENDY_H 38 | #include "gendy_waveform.h" 39 | // 40 | // gendy~ version 0.6.0: 41 | const int GENDY_MAJ = 0; 42 | const int GENDY_MIN = 6; 43 | const int GENDY_REV = 0; 44 | 45 | // A flext dsp external ("tilde object") inherits from the class flext_dsp 46 | class gendy: public flext_dsp { 47 | // flext macro magic 48 | FLEXT_HEADER_S(gendy, flext_dsp, class_setup) 49 | 50 | public: 51 | gendy(); 52 | ~gendy(); 53 | 54 | protected: 55 | // here we declare the virtual DSP function 56 | virtual void m_signal(int n, float *const *in, float *const *out); 57 | 58 | // Message handling functions 59 | void set_frequency(float new_freq); 60 | void set_num_breakpoints(float num_breakpoints); 61 | void set_h_step(float new_stepsize); 62 | void set_v_step(float new_stepsize); 63 | void set_h_pull(float new_pull); 64 | void set_v_pull(float new_pull); 65 | void set_interpolation_lin(); 66 | void set_interpolation_cubic(); 67 | void set_interpolation_spline(); 68 | void set_interpolation_sinc(); 69 | void set_waveform_flat(); 70 | void set_waveform_sine(); 71 | void set_waveform_square(); 72 | void set_debug(int new_debug); 73 | void set_outbuf(short argc, t_atom *argv); 74 | void redraw(); 75 | 76 | private: 77 | gendy_waveform waveform; 78 | static bool debug; 79 | // class-wide variable to keep track of how many objects exist 80 | static unsigned int gendy_count; 81 | // instance ID 82 | unsigned int id; 83 | 84 | // waveform display buffer variables 85 | // buffer to copy to for waveform display 86 | flext::buffer *display_buf; 87 | 88 | // Internal class methods 89 | static void class_setup(t_classid thisclass); 90 | void set_interpolation(interpolation_t interpolation); 91 | void set_waveform(waveshape_t waveform); 92 | 93 | // register the callbacks, and tell flext their calling format 94 | FLEXT_CALLBACK_F(set_frequency) 95 | FLEXT_CALLBACK_I(set_num_breakpoints) 96 | FLEXT_CALLBACK_F(set_h_step) 97 | FLEXT_CALLBACK_F(set_v_step) 98 | FLEXT_CALLBACK_F(set_h_pull) 99 | FLEXT_CALLBACK_F(set_v_pull) 100 | FLEXT_CALLBACK(set_interpolation_lin) 101 | FLEXT_CALLBACK(set_interpolation_cubic) 102 | FLEXT_CALLBACK(set_interpolation_spline) 103 | FLEXT_CALLBACK(set_interpolation_sinc) 104 | FLEXT_CALLBACK(set_waveform_flat) 105 | FLEXT_CALLBACK(set_waveform_sine) 106 | FLEXT_CALLBACK(set_waveform_square) 107 | FLEXT_CALLBACK_I(set_debug) 108 | FLEXT_CALLBACK_V(set_outbuf) 109 | FLEXT_CALLBACK(redraw) 110 | }; 111 | unsigned int gendy::gendy_count = 0; 112 | bool gendy::debug = true; 113 | #endif /* GENDY_H */ 114 | -------------------------------------------------------------------------------- /src/log.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #include "log.h" 31 | #include 32 | 33 | // shows msg if allowed by LOG_LEVEL 34 | void print_log(const char *msg, int level){ 35 | if (LOG_LEVEL >= level) { 36 | post(msg); 37 | } 38 | } 39 | 40 | void print_log(const char *msg, int arg1, int level){ 41 | if (LOG_LEVEL >= level) { 42 | post(msg, arg1); 43 | } 44 | } 45 | 46 | void print_log(const char *msg, int arg1, int arg2, int arg3, int level) { 47 | if (LOG_LEVEL >= level) { 48 | post(msg, arg1, arg2, arg3); 49 | } 50 | } 51 | 52 | void print_log(const char *msg, unsigned int arg1, int level){ 53 | if (LOG_LEVEL >= level) { 54 | post(msg, arg1); 55 | } 56 | } 57 | 58 | void print_log(const char *msg, float arg1, int level){ 59 | if (LOG_LEVEL >= level) { 60 | post(msg, arg1); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef LOG_H 31 | #define LOG_H 32 | 33 | // define and set log levels 34 | #define LOG_NONE 0 35 | #define LOG_ERROR 1 36 | #define LOG_INFO 2 37 | #define LOG_DEBUG 3 38 | 39 | #define LOG_LEVEL LOG_INFO 40 | 41 | void print_log(const char *msg, int level); 42 | void print_log(const char *msg, int arg1, int level); 43 | void print_log(const char *msg, int arg1, int arg2, int arg3, int level); 44 | void print_log(const char *msg, unsigned int arg1, int level); 45 | void print_log(const char *msg, float arg1, int level); 46 | 47 | #endif /* LOG_H */ 48 | -------------------------------------------------------------------------------- /src/splines.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #include "splines.h" 31 | 32 | void get_cspline_coefs(double *xp, double *yp, double *coefs) { 33 | double h[3]; 34 | // h[n] is the x-distance between x[n] and x[n+1] 35 | for(int i = 0; i < 3; i++) 36 | h[i] = xp[i+1] - xp[i]; 37 | // d[i] is the slope of the line segment connecting point i 38 | // to point i+1 39 | double d[3]; 40 | for(int i = 0; i < 3; i++) 41 | d[i] = (yp[i+1] - yp[i]) / h[i]; 42 | //yd[n] is the derivitive of f(x) at xp[1] and xp[2]. It's a 43 | //weighted average of the two adjacent line segments 44 | double yd[3]; 45 | for(int i = 1; i < 3; i++) 46 | yd[i] = (d[i] * h[i-1] + d[i-1] * h[i]) / (h[i-1] + h[i]); 47 | // Here we actually calculate the coefficients 48 | coefs[0] = (h[1]*(yd[2] - yd[1]) - 49 | 2 * (yp[2] - yp[1] - h[1] * yd[1])) / (h[1] * h[1] * h[1]); 50 | coefs[1] = (3 * (yp[2] - yp[1] - h[1] * yd[1]) - 51 | h[1] * (yd[2] - yd[1])) / (h[1] * h[1]); 52 | coefs[2] = yd[1]; 53 | coefs[3] = yp[1]; 54 | } 55 | 56 | double cspline_interp(double *coefs, double x) { 57 | return coefs[3] + x * (coefs[2] + x * (coefs[1] + coefs[0] * x)); 58 | } 59 | -------------------------------------------------------------------------------- /src/splines.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef SPLINES_H 31 | #define SPLINES_H 32 | 33 | void get_cspline_coefs(double *xp, double *yp, double *coefs); 34 | double cspline_interp(double *coefs, double x); 35 | 36 | #endif /* SPLINES_H */ 37 | -------------------------------------------------------------------------------- /src/types.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef TYPES_H 31 | #define TYPES_H 32 | 33 | // define interpolation types 34 | enum interpolation_t{ LINEAR, CUBIC, SPLINE, SINC }; 35 | 36 | // define center waveform shapes 37 | enum waveshape_t { FLAT, SINE, SQUARE, TRIANGLE, SAWTOOTH }; 38 | 39 | // define data types 40 | typedef float gendydur_t; 41 | typedef float gendyamp_t; 42 | typedef float gendysamp_t; 43 | 44 | #endif /* TYPES_H */ 45 | -------------------------------------------------------------------------------- /src/util.cpp: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #include "util.h" 31 | #include 32 | #include 33 | 34 | // return a uniformly distributed double-precision float between 0 and 1 35 | double randf() { 36 | return rand() / (double)RAND_MAX; 37 | } 38 | 39 | // returns gaussian random variable with mu 0 and sigma 1 40 | // From the GNU Scientific Library, src/randist/gauss.c 41 | 42 | double gauss() { 43 | double x, y, r2; 44 | do { 45 | /* choose x,y in uniform square (-1,-1) to (+1,+1) */ 46 | x = -1 + 2 * randf(); 47 | y = -1 + 2 * randf(); 48 | 49 | /* see if it is in the unit circle */ 50 | r2 = x * x + y * y; 51 | } while (r2 > 1.0 || r2 == 0); 52 | 53 | /* Box-Muller transform */ 54 | return y * sqrt (-2.0 * log(r2) / r2); 55 | } 56 | 57 | int round(float num) { 58 | return int(floor(num + 0.5)); 59 | } 60 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | /********************************************* 2 | * 3 | * libgendy 4 | * 5 | * a library implementing Iannis Xenakis's Dynamic Stochastic Synthesis 6 | * 7 | * Copyright 2009,2010 Spencer Russell 8 | * Released under the GPLv3 9 | * 10 | * This file is part of libgendy. 11 | * 12 | * libgendy is free software: you can redistribute it and/or 13 | * modify it under the terms of the GNU General Public License version 3 as 14 | * published by the Free Software Foundation. 15 | * 16 | * libgendy is distributed in the hope that it will be useful, but 17 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 18 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 19 | * more details. 20 | * 21 | * You should have received a copy of the GNU General Public License along with 22 | * libgendy. If not, see . 23 | * 24 | * 25 | ********************************************/ 26 | 27 | 28 | 29 | 30 | #ifndef UTIL_H 31 | #define UTIL_H 32 | 33 | // misc utility functions 34 | 35 | // return a uniformly distributed double-precision float between 0 and 1 36 | double randf(); 37 | 38 | // returns gaussian random variable with mu 0 and sigma 1 39 | // From the GNU Scientific Library, src/randist/gauss.c, released under GPL 40 | double gauss(); 41 | 42 | // returns nearest integer. X.5 always rounded to X+1, so it's non-symmetrical 43 | int round(float num); 44 | 45 | #endif /* UTIL_H */ 46 | --------------------------------------------------------------------------------