├── .cproject ├── .project ├── Makefile ├── README ├── analogue.png ├── analogue.sh ├── analogue.ttl ├── analogue.xcf ├── faust ├── amps.dsp ├── analogue-poly.dsp ├── analogue.dsp ├── dynamic.dsp ├── effects.dsp ├── filters.dsp ├── freeverb.dsp ├── midi.dsp ├── oscdemo.dsp ├── oscillators.dsp ├── simple.dsp ├── standalone-poly.dsp ├── standalone.dsp ├── test.dsp ├── test2.dsp └── utils.dsp ├── manifest.ttl ├── portmeta.py ├── src ├── analogue-common.h ├── analogue-gui-test.cpp ├── analogue-gui.cpp ├── analogue.cpp ├── analogue.h ├── changeable.h ├── collector-ui.h ├── comboboxes-test.cpp ├── comboboxes.h ├── dsp.cpp ├── dsp.h ├── dump-rdf.h ├── knob-test.cpp ├── knob.h ├── long-note-test.cpp ├── panel.h ├── printttl.cpp └── toggle.h └── test ├── dpw.dsp ├── oscillators.py ├── saw-test.dsp ├── saw2-test.dsp ├── sin-test.dsp ├── sin2-test.dsp ├── square-test.dsp ├── square2-test.dsp ├── tests.cpp ├── tri-test.dsp └── tri2-test.dsp /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | analogue 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | ?name? 14 | 15 | 16 | 17 | org.eclipse.cdt.make.core.append_environment 18 | true 19 | 20 | 21 | org.eclipse.cdt.make.core.autoBuildTarget 22 | all 23 | 24 | 25 | org.eclipse.cdt.make.core.buildArguments 26 | 27 | 28 | 29 | org.eclipse.cdt.make.core.buildCommand 30 | make 31 | 32 | 33 | org.eclipse.cdt.make.core.cleanBuildTarget 34 | clean 35 | 36 | 37 | org.eclipse.cdt.make.core.contents 38 | org.eclipse.cdt.make.core.activeConfigSettings 39 | 40 | 41 | org.eclipse.cdt.make.core.enableAutoBuild 42 | false 43 | 44 | 45 | org.eclipse.cdt.make.core.enableCleanBuild 46 | true 47 | 48 | 49 | org.eclipse.cdt.make.core.enableFullBuild 50 | true 51 | 52 | 53 | org.eclipse.cdt.make.core.fullBuildTarget 54 | all 55 | 56 | 57 | org.eclipse.cdt.make.core.stopOnError 58 | true 59 | 60 | 61 | org.eclipse.cdt.make.core.useDefaultBuildCmd 62 | true 63 | 64 | 65 | 66 | 67 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 68 | full,incremental, 69 | 70 | 71 | 72 | 73 | 74 | org.eclipse.cdt.core.cnature 75 | org.eclipse.cdt.core.ccnature 76 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 77 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 78 | 79 | 80 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | BUNDLE = Analogue.lv2 2 | INSTALL_DIR = /usr/local/lib/lv2 3 | ALSA_GTK = `pkg-config --cflags --libs alsa` `pkg-config --cflags --libs gtk+-2.0` 4 | JACK_GTK = `pkg-config --cflags --libs jack` `pkg-config --cflags --libs gtk+-2.0` 5 | GTKMM = `pkg-config --cflags --libs gtkmm-2.4` 6 | LV2 = `pkg-config --cflags --libs lv2-plugin` 7 | LV2_GUI = `pkg-config --cflags --libs lv2-gui` 8 | FAUST = -I/usr/local/lib/faust/ 9 | TESTS = gen/saw.cpp gen/saw2.cpp gen/sin.cpp gen/sin2.cpp gen/square.cpp gen/square2.cpp gen/tri.cpp gen/tri2.cpp 10 | 11 | #CFLAGS=-O3 -mtune=native -march=native -mfpmath=sse -ffast-math -ftree-vectorize 12 | CFLAGS=-mtune=native -march=native -mfpmath=sse -ffast-math -ftree-vectorize 13 | 14 | $(BUNDLE): manifest.ttl analogue.ttl Analogue.so AnalogueGUI.so 15 | rm -rf $(BUNDLE) 16 | mkdir $(BUNDLE) 17 | cp $^ $(BUNDLE) 18 | 19 | Analogue.so: src/analogue.cpp gen gen/analogue.peg gen/analogue-meta.h gen/dsp.cpp 20 | g++ -shared -Wall -fPIC -DPIC src/analogue.cpp src/dsp.cpp $(LV2) $(FAUST) $(CFLAGS) -Igen/ -lm -o Analogue.so 21 | 22 | AnalogueGUI.so: src/analogue-gui.cpp gen gen/analogue.peg gen/analogue-meta.h 23 | g++ -shared -Wall -fPIC -DPIC src/analogue-gui.cpp $(GTKMM) $(LV2) $(LV2_GUI) $(CFLAGS) -Igen/ -o AnalogueGUI.so 24 | 25 | guitest: src/analogue-gui.cpp gen/analogue.peg gen/analogue-meta.h 26 | g++ -Wall src/analogue-gui-test.cpp $(GTKMM) $(LV2) $(CFLAGS) -Igen/ -o guitest.out 27 | 28 | knobtest: 29 | g++ -Wall src/knob-test.cpp $(GTKMM) $(LV2) $(CFLAGS) -Igen/ -o knobtest.out 30 | 31 | comboboxestest: 32 | g++ -Wall src/comboboxes-test.cpp $(GTKMM) $(LV2) $(CFLAGS) -Igen/ -o comboboxestest.out 33 | 34 | gen: 35 | mkdir gen 36 | 37 | gen/dsp.cpp: gen 38 | faust -fun -vec -a minimal.cpp faust/analogue-poly.dsp > gen/dsp.cpp 39 | 40 | gen/analogue.peg: gen 41 | lv2peg analogue.ttl gen/analogue.peg 42 | 43 | gen/analogue-meta.h: gen 44 | python portmeta.py 45 | 46 | standalone: 47 | faust -fun -vec -a alsa-gtk.cpp faust/standalone.dsp > gen/standalone.cpp 48 | g++ -Wall gen/standalone.cpp $(ALSA_GTK) $(FAUST) $(CFLAGS) -lm -o standalone.out 49 | 50 | poly: 51 | faust -sch -fun -vec -a alsa-gtk.cpp faust/standalone-poly.dsp > gen/standalone-poly.cpp 52 | g++ -Wall gen/standalone-poly.cpp $(ALSA_GTK) $(FAUST) $(CFLAGS) -lm -o standalone-poly.out 53 | 54 | oscdemo: 55 | faust -fun -vec -a alsa-gtk.cpp faust/oscdemo.dsp > gen/oscdemo.cpp 56 | g++ -Wall gen/oscdemo.cpp $(ALSA_GTK) $(FAUST) $(CFLAGS) -lm -o oscdemo.out 57 | 58 | simple: 59 | faust -fun -vec -a alsa-gtk.cpp faust/simple.dsp > gen/simple.cpp 60 | g++ -Wall gen/simple.cpp $(ALSA_GTK) $(FAUST) $(CFLAGS) -lm -o simple.out 61 | 62 | test2: 63 | faust -fun -vec -a alsa-gtk.cpp faust/test2.dsp > gen/test2.cpp 64 | g++ -Wall gen/test2.cpp $(ALSA_GTK) $(FAUST) $(CFLAGS) -lm -o test2.out 65 | 66 | gen/%.cpp: test/%-test.dsp 67 | faust -a minimal.cpp -cn $(patsubst gen/%.cpp,%,$@)dsp $< > $@ 68 | 69 | tests: $(TESTS) 70 | g++ -Wall -fpermissive test/tests.cpp $(FAUST) -lm -Igen/ -Isrc/ -lsndfile -o tests.out 71 | ./tests.out 72 | 73 | dumpports: gen/dsp.cpp 74 | g++ -Wall src/printttl.cpp src/dsp.cpp $(PAQ) $(FAUST) -lm -lsndfile -o dumpports.out 75 | ./dumpports.out > gen/ports.ttl 76 | 77 | svg: 78 | faust -svg faust/analogue.dsp 79 | faust -svg faust/analogue-poly.dsp 80 | faust -svg faust/oscdemo.dsp 81 | faust -svg faust/standalone.dsp 82 | faust -svg faust/simple.dsp 83 | 84 | install: $(BUNDLE) 85 | mkdir -p $(INSTALL_DIR) 86 | rm -rf $(INSTALL_DIR)/$(BUNDLE) 87 | cp -R $(BUNDLE) $(INSTALL_DIR) 88 | 89 | clean: 90 | rm -rf $(BUNDLE) *.so *.out gen/* faust/*-svg 91 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Analogue synth by Timo Westkämper 2 | 3 | 2 * LFO 4 | 2 * OSC 5 | 1 * Noise 6 | 2 * FILTER (incl ENV) 7 | 2 * AMP (incl ENV) 8 | 9 | CONTENT 10 | 11 | analogue.dsp - main DSP script 12 | amps.dsp - amplifier definitions 13 | filters.dsp - filter definitions 14 | midi.dsp - MIDI controls 15 | oscillators.dsp - oscillators 16 | utils.dsp - various utilities 17 | 18 | simple.dsp - simple version for testing 19 | standalone.dsp - standalone version 20 | oscdemo.dsp - standalone oscillator 21 | 22 | DEPENDENCIES 23 | 24 | * FAUST 2.* 25 | * lv2-c++-tools 26 | * GTK 3.* 27 | * GTKMM 3.* 28 | * ALSA (for standalone code) 29 | -------------------------------------------------------------------------------- /analogue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timowest/analogue/a9b0bd4c5d7b4473f898dcf70c21fcb0e08f7f43/analogue.png -------------------------------------------------------------------------------- /analogue.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | zynjacku http://www.westkamper.com/lv2/analogue 3 | -------------------------------------------------------------------------------- /analogue.ttl: -------------------------------------------------------------------------------- 1 | @prefix lv2: . 2 | @prefix doap: . 3 | @prefix foaf: . 4 | @prefix rdf: . 5 | @prefix rdfs: . 6 | @prefix ll: . 7 | @prefix pg: . 8 | @prefix ev: . 9 | @prefix ui: . 10 | 11 | @prefix ext: . 12 | 13 | 14 | a ui:GtkUI; 15 | ui:binary ; 16 | ui:requiredFeature ui:makeResident; 17 | ui:optionalFeature ui:Event. 18 | 19 | a pg:StereoGroup. 20 | 21 | 22 | a lv2:Plugin, lv2:InstrumentPlugin; 23 | lv2:binary ; 24 | doap:name "analogue"; 25 | doap:maintainer [ 26 | a foaf:Person; 27 | foaf:name "Timo Westkämper" 28 | ]; 29 | doap:license ; 30 | ll:pegName "p"; 31 | ui:ui ; 32 | 33 | lv2:port [ 34 | a ev:EventPort, lv2:InputPort; 35 | lv2:index 0; 36 | ev:supportsEvent ; 37 | lv2:symbol "midi"; 38 | lv2:name "MIDI"; 39 | ], 40 | 41 | [ 42 | a lv2:AudioPort, lv2:OutputPort; 43 | lv2:index 1; 44 | lv2:symbol "audio_l"; 45 | lv2:name "Left"; 46 | pg:membership [ 47 | pg:group ; 48 | pg:role pg:leftChannel; 49 | ]; 50 | ], 51 | 52 | [ 53 | a lv2:AudioPort, lv2:OutputPort; 54 | lv2:index 2; 55 | lv2:symbol "audio_r"; 56 | lv2:name "Right"; 57 | pg:membership [ 58 | pg:group ; 59 | pg:role pg:rightChannel; 60 | ]; 61 | ], 62 | 63 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 3; lv2:symbol "amp_output"; lv2:name "output"; 64 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 65 | 66 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 4; lv2:symbol "amp1_attack"; lv2:name "attack"; 67 | lv2:minimum 0.000000; lv2:maximum 2.000000; lv2:default 0.000000; ext:step 0.005000 ], 68 | 69 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 5; lv2:symbol "amp1_decay"; lv2:name "decay"; 70 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 71 | 72 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 6; lv2:symbol "amp1_env_to_pan"; lv2:name "env_to_pan"; 73 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 74 | 75 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 7; lv2:symbol "amp1_kbd_to_level"; lv2:name "kbd_to_level"; 76 | lv2:minimum -0.100000; lv2:maximum 0.100000; lv2:default 0.000000; ext:step 0.010000 ], 77 | 78 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 8; lv2:symbol "amp1_kbd_to_pan"; lv2:name "kbd_to_pan"; 79 | lv2:minimum -0.100000; lv2:maximum 0.100000; lv2:default 0.000000; ext:step 0.010000 ], 80 | 81 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 9; lv2:symbol "amp1_level"; lv2:name "level"; 82 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 83 | 84 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 10; lv2:symbol "amp1_lfo_to_level"; lv2:name "lfo_to_level"; 85 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 86 | 87 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 11; lv2:symbol "amp1_lfo_to_pan"; lv2:name "lfo_to_pan"; 88 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 89 | 90 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 12; lv2:symbol "amp1_pan"; lv2:name "pan"; 91 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 92 | 93 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 13; lv2:symbol "amp1_power"; lv2:name "power"; 94 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 95 | 96 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 14; lv2:symbol "amp1_release"; lv2:name "release"; 97 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 98 | 99 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 15; lv2:symbol "amp1_sustain"; lv2:name "sustain"; 100 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 101 | 102 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 16; lv2:symbol "amp2_attack"; lv2:name "attack"; 103 | lv2:minimum 0.000000; lv2:maximum 2.000000; lv2:default 0.000000; ext:step 0.005000 ], 104 | 105 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 17; lv2:symbol "amp2_decay"; lv2:name "decay"; 106 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 107 | 108 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 18; lv2:symbol "amp2_env_to_pan"; lv2:name "env_to_pan"; 109 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 110 | 111 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 19; lv2:symbol "amp2_kbd_to_level"; lv2:name "kbd_to_level"; 112 | lv2:minimum -0.100000; lv2:maximum 0.100000; lv2:default 0.000000; ext:step 0.010000 ], 113 | 114 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 20; lv2:symbol "amp2_kbd_to_pan"; lv2:name "kbd_to_pan"; 115 | lv2:minimum -0.100000; lv2:maximum 0.100000; lv2:default 0.000000; ext:step 0.010000 ], 116 | 117 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 21; lv2:symbol "amp2_level"; lv2:name "level"; 118 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 119 | 120 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 22; lv2:symbol "amp2_lfo_to_level"; lv2:name "lfo_to_level"; 121 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 122 | 123 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 23; lv2:symbol "amp2_lfo_to_pan"; lv2:name "lfo_to_pan"; 124 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 125 | 126 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 24; lv2:symbol "amp2_pan"; lv2:name "pan"; 127 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 128 | 129 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 25; lv2:symbol "amp2_power"; lv2:name "power"; 130 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 131 | 132 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 26; lv2:symbol "amp2_release"; lv2:name "release"; 133 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 134 | 135 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 27; lv2:symbol "amp2_sustain"; lv2:name "sustain"; 136 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 137 | 138 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 28; lv2:symbol "effects_delay_bypass"; lv2:name "bypass"; 139 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 140 | 141 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 29; lv2:symbol "effects_delay_cutoff"; lv2:name "cutoff"; 142 | lv2:minimum 0.000000; lv2:maximum 10000.000000; lv2:default 200.000000; ext:step 10.000000 ], 143 | 144 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 30; lv2:symbol "effects_delay_depth"; lv2:name "depth"; 145 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 146 | 147 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 31; lv2:symbol "effects_delay_length"; lv2:name "length"; 148 | lv2:minimum 0.000000; lv2:maximum 1000.000000; lv2:default 10.000000; ext:step 1.000000 ], 149 | 150 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 32; lv2:symbol "effects_delay_mix"; lv2:name "mix"; 151 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 152 | 153 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 33; lv2:symbol "effects_flanger_bypass"; lv2:name "bypass"; 154 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 155 | 156 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 34; lv2:symbol "effects_flanger_feedback"; lv2:name "feedback"; 157 | lv2:minimum -0.999000; lv2:maximum 0.999000; lv2:default 0.000000; ext:step 0.001000 ], 158 | 159 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 35; lv2:symbol "effects_flanger_flange_delay"; lv2:name "flange_delay"; 160 | lv2:minimum 0.000000; lv2:maximum 20.000000; lv2:default 10.000000; ext:step 0.001000 ], 161 | 162 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 36; lv2:symbol "effects_flanger_invert"; lv2:name "invert"; 163 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 164 | 165 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 37; lv2:symbol "effects_flanger_mix"; lv2:name "mix"; 166 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 167 | 168 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 38; lv2:symbol "effects_flanger_speed"; lv2:name "speed"; 169 | lv2:minimum 0.000000; lv2:maximum 10.000000; lv2:default 0.500000; ext:step 0.010000 ], 170 | 171 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 39; lv2:symbol "effects_reverb_bypass"; lv2:name "bypass"; 172 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 173 | 174 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 40; lv2:symbol "effects_reverb_damp"; lv2:name "damp"; 175 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.720000; ext:step 0.025000 ], 176 | 177 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 41; lv2:symbol "effects_reverb_mix"; lv2:name "mix"; 178 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.141000; ext:step 0.025000 ], 179 | 180 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 42; lv2:symbol "effects_reverb_roomSize"; lv2:name "roomSize"; 181 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.540000; ext:step 0.025000 ], 182 | 183 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 43; lv2:symbol "filter1_attack"; lv2:name "attack"; 184 | lv2:minimum 0.000000; lv2:maximum 2.000000; lv2:default 0.000000; ext:step 0.005000 ], 185 | 186 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 44; lv2:symbol "filter1_bypass"; lv2:name "bypass"; 187 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 188 | 189 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 45; lv2:symbol "filter1_cutoff"; lv2:name "cutoff"; 190 | lv2:minimum 0.000000; lv2:maximum 5000.000000; lv2:default 440.000000; ext:step 10.000000 ], 191 | 192 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 46; lv2:symbol "filter1_decay"; lv2:name "decay"; 193 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 194 | 195 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 47; lv2:symbol "filter1_env_to_f"; lv2:name "env_to_f"; 196 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 197 | 198 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 48; lv2:symbol "filter1_env_to_q"; lv2:name "env_to_q"; 199 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.100000 ], 200 | 201 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 49; lv2:symbol "filter1_kbd"; lv2:name "kbd"; 202 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 1.000000; ext:step 0.100000 ], 203 | 204 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 50; lv2:symbol "filter1_lfo_to_f"; lv2:name "lfo_to_f"; 205 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 206 | 207 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 51; lv2:symbol "filter1_lfo_to_q"; lv2:name "lfo_to_q"; 208 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.100000 ], 209 | 210 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 52; lv2:symbol "filter1_q"; lv2:name "q"; 211 | lv2:minimum 0.000000; lv2:maximum 10.000000; lv2:default 0.500000; ext:step 0.010000 ], 212 | 213 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 53; lv2:symbol "filter1_release"; lv2:name "release"; 214 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 215 | 216 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 54; lv2:symbol "filter1_sustain"; lv2:name "sustain"; 217 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 218 | 219 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 55; lv2:symbol "filter1_to_f2"; lv2:name "to_f2"; 220 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 221 | 222 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 56; lv2:symbol "filter1_type"; lv2:name "type"; 223 | lv2:minimum 0.000000; lv2:maximum 3.000000; lv2:default 0.000000; ext:step 1.000000 ], 224 | 225 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 57; lv2:symbol "filter2_attack"; lv2:name "attack"; 226 | lv2:minimum 0.000000; lv2:maximum 2.000000; lv2:default 0.000000; ext:step 0.005000 ], 227 | 228 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 58; lv2:symbol "filter2_bypass"; lv2:name "bypass"; 229 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 230 | 231 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 59; lv2:symbol "filter2_cutoff"; lv2:name "cutoff"; 232 | lv2:minimum 0.000000; lv2:maximum 5000.000000; lv2:default 440.000000; ext:step 10.000000 ], 233 | 234 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 60; lv2:symbol "filter2_decay"; lv2:name "decay"; 235 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 236 | 237 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 61; lv2:symbol "filter2_env_to_f"; lv2:name "env_to_f"; 238 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 239 | 240 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 62; lv2:symbol "filter2_env_to_q"; lv2:name "env_to_q"; 241 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.100000 ], 242 | 243 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 63; lv2:symbol "filter2_kbd"; lv2:name "kbd"; 244 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 1.000000; ext:step 0.100000 ], 245 | 246 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 64; lv2:symbol "filter2_lfo_to_f"; lv2:name "lfo_to_f"; 247 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 248 | 249 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 65; lv2:symbol "filter2_lfo_to_q"; lv2:name "lfo_to_q"; 250 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.100000 ], 251 | 252 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 66; lv2:symbol "filter2_q"; lv2:name "q"; 253 | lv2:minimum 0.000000; lv2:maximum 10.000000; lv2:default 0.500000; ext:step 0.010000 ], 254 | 255 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 67; lv2:symbol "filter2_release"; lv2:name "release"; 256 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 1.000000; ext:step 0.010000 ], 257 | 258 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 68; lv2:symbol "filter2_sustain"; lv2:name "sustain"; 259 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 1.000000; ext:step 0.010000 ], 260 | 261 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 69; lv2:symbol "filter2_type"; lv2:name "type"; 262 | lv2:minimum 0.000000; lv2:maximum 3.000000; lv2:default 0.000000; ext:step 1.000000 ], 263 | 264 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 70; lv2:symbol "lfo1_delay"; lv2:name "delay"; 265 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 266 | 267 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 71; lv2:symbol "lfo1_fade_in"; lv2:name "fade_in"; 268 | lv2:minimum 0.000000; lv2:maximum 5.000000; lv2:default 0.000000; ext:step 0.010000 ], 269 | 270 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 72; lv2:symbol "lfo1_freq"; lv2:name "freq"; 271 | lv2:minimum 1.000000; lv2:maximum 50.000000; lv2:default 1.000000; ext:step 1.000000 ], 272 | 273 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 73; lv2:symbol "lfo1_power"; lv2:name "power"; 274 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 275 | 276 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 74; lv2:symbol "lfo1_type"; lv2:name "type"; 277 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 0.000000; ext:step 1.000000 ], 278 | 279 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 75; lv2:symbol "lfo1_width"; lv2:name "width"; 280 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 281 | 282 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 76; lv2:symbol "lfo2_delay"; lv2:name "delay"; 283 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 284 | 285 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 77; lv2:symbol "lfo2_fade_in"; lv2:name "fade_in"; 286 | lv2:minimum 0.000000; lv2:maximum 5.000000; lv2:default 0.000000; ext:step 0.010000 ], 287 | 288 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 78; lv2:symbol "lfo2_freq"; lv2:name "freq"; 289 | lv2:minimum 1.000000; lv2:maximum 50.000000; lv2:default 1.000000; ext:step 1.000000 ], 290 | 291 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 79; lv2:symbol "lfo2_power"; lv2:name "power"; 292 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 293 | 294 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 80; lv2:symbol "lfo2_type"; lv2:name "type"; 295 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 0.000000; ext:step 1.000000 ], 296 | 297 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 81; lv2:symbol "lfo2_width"; lv2:name "width"; 298 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 299 | 300 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 82; lv2:symbol "noise_color"; lv2:name "color"; 301 | lv2:minimum 200.000000; lv2:maximum 5000.000000; lv2:default 2000.000000; ext:step 50.000000 ], 302 | 303 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 83; lv2:symbol "noise_f1_to_f2"; lv2:name "f1_to_f2"; 304 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 305 | 306 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 84; lv2:symbol "noise_level"; lv2:name "level"; 307 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 308 | 309 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 85; lv2:symbol "noise_power"; lv2:name "power"; 310 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 311 | 312 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 86; lv2:symbol "osc1_f1_to_f2"; lv2:name "f1_to_f2"; 313 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 314 | 315 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 87; lv2:symbol "osc1_finetune"; lv2:name "finetune"; 316 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 317 | 318 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 88; lv2:symbol "osc1_kbd"; lv2:name "kbd"; 319 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 1.000000; ext:step 0.100000 ], 320 | 321 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 89; lv2:symbol "osc1_level"; lv2:name "level"; 322 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 323 | 324 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 90; lv2:symbol "osc1_lfo_to_p"; lv2:name "lfo_to_p"; 325 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 326 | 327 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 91; lv2:symbol "osc1_lfo_to_w"; lv2:name "lfo_to_w"; 328 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 329 | 330 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 92; lv2:symbol "osc1_power"; lv2:name "power"; 331 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 332 | 333 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 93; lv2:symbol "osc1_tune"; lv2:name "tune"; 334 | lv2:minimum -24.000000; lv2:maximum 24.000000; lv2:default 0.000000; ext:step 1.000000 ], 335 | 336 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 94; lv2:symbol "osc1_type"; lv2:name "type"; 337 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 0.000000; ext:step 1.000000 ], 338 | 339 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 95; lv2:symbol "osc1_width"; lv2:name "width"; 340 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 341 | 342 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 96; lv2:symbol "osc2_f1_to_f2"; lv2:name "f1_to_f2"; 343 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 344 | 345 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 97; lv2:symbol "osc2_finetune"; lv2:name "finetune"; 346 | lv2:minimum -1.000000; lv2:maximum 1.000000; lv2:default 0.000000; ext:step 0.010000 ], 347 | 348 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 98; lv2:symbol "osc2_kbd"; lv2:name "kbd"; 349 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 1.000000; ext:step 0.100000 ], 350 | 351 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 99; lv2:symbol "osc2_level"; lv2:name "level"; 352 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ], 353 | 354 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 100; lv2:symbol "osc2_lfo_to_p"; lv2:name "lfo_to_p"; 355 | lv2:minimum -12.000000; lv2:maximum 12.000000; lv2:default 0.000000; ext:step 0.100000 ], 356 | 357 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 101; lv2:symbol "osc2_lfo_to_w"; lv2:name "lfo_to_w"; 358 | lv2:minimum -0.500000; lv2:maximum 0.500000; lv2:default 0.000000; ext:step 0.010000 ], 359 | 360 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 102; lv2:symbol "osc2_power"; lv2:name "power"; 361 | lv2:minimum 0.000000; lv2:maximum 0.000000; lv2:default 1.000000; ext:step 1.000000 ], 362 | 363 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 103; lv2:symbol "osc2_tune"; lv2:name "tune"; 364 | lv2:minimum -24.000000; lv2:maximum 24.000000; lv2:default 0.000000; ext:step 1.000000 ], 365 | 366 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 104; lv2:symbol "osc2_type"; lv2:name "type"; 367 | lv2:minimum 0.000000; lv2:maximum 4.000000; lv2:default 0.000000; ext:step 1.000000 ], 368 | 369 | [ a lv2:ControlPort, lv2:InputPort; lv2:index 105; lv2:symbol "osc2_width"; lv2:name "width"; 370 | lv2:minimum 0.000000; lv2:maximum 1.000000; lv2:default 0.500000; ext:step 0.010000 ]. 371 | 372 | -------------------------------------------------------------------------------- /analogue.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timowest/analogue/a9b0bd4c5d7b4473f898dcf70c21fcb0e08f7f43/analogue.xcf -------------------------------------------------------------------------------- /faust/amps.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("music.lib"); 16 | 17 | import("utils.dsp"); 18 | 19 | // amplifiers 20 | 21 | // in : gate, gain, pitch, lfo 22 | amp1 = vgroup("amp1", multiselect(2, checkbox("power"), 0, 0, amp)); 23 | 24 | // in : gate, gain, pitch, lfo 25 | amp2 = vgroup("amp2", multiselect(2, checkbox("power"), 0, 0, amp)); 26 | 27 | amp(gate, gain, pitch, lfo) = ((gate : env), _) <: (_,!,level*_*_) : amp_stereo(pitch, lfo) 28 | with { 29 | level = main_level + (kbd_to_level * (pitch - A4)) + (lfo_to_level * lfo) : (_*gain) : normalize(0,1); 30 | kbd_to_level = hslider("kbd_to_level", 0, -0.1, 0.1, 0.01) * 0.1; 31 | lfo_to_level = hslider("lfo_to_level", 0, -0.5, 0.5, 0.01); 32 | //gain_to_level = hslider("gain_to_level", 1, 0, 1, 0.01); 33 | main_level = hslider("level", 1, 0, 1, 0.01); 34 | }; 35 | 36 | amp_stereo(pitch, lfo, env) = to_stereo(0.5 * (pan+1)) 37 | with { 38 | pan = main_pan + (kbd_to_pan * (pitch - A4)) + (lfo_to_pan * lfo) + (env_to_pan * env) : normalize(-1,1); 39 | main_pan = hslider("pan", 0, -1, 1, 0.01); 40 | kbd_to_pan = hslider("kbd_to_pan", 0, -0.1, 0.1, 0.01) * 0.1; 41 | lfo_to_pan = hslider("lfo_to_pan", 0, -0.5, 0.5, 0.01); 42 | env_to_pan = hslider("env_to_pan", 0, -0.5, 0.5, 0.01); 43 | }; 44 | 45 | to_stereo(pan) = _ <: (1-pan)*_, pan*_; 46 | 47 | -------------------------------------------------------------------------------- /faust/analogue-poly.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | analogue = library("analogue.dsp"); 16 | import("effects.dsp"); 17 | 18 | // Polyphonic Analogue Synth 19 | 20 | // TODO : render only active voices 21 | voice(i) = analogue.voice(gate(i), gain(i), pitch(i)) 22 | with { 23 | gate(i) = button("/h:midi/gate%i"); 24 | gain(i) = nentry("/h:midi/gain%i", 0, 0, 1, 0.01); 25 | pitch(i) = hslider("/h:midi/pitch%i", 64, 32, 100, 1); 26 | }; 27 | 28 | main_out = nentry("/h:amp/output", 1, 0, 1, 0.01); // TODO in dB 29 | 30 | // TODO : effects 31 | process = par(i, 8, voice(i)) :> (_,_,_,_) : effects :> (main_out * _, main_out * _); 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /faust/analogue.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("music.lib"); 16 | 17 | import("midi.dsp"); 18 | filters = library("filters.dsp"); 19 | oscillators = library("oscillators.dsp"); 20 | amps = library("amps.dsp"); 21 | 22 | import("effects.dsp"); 23 | import("utils.dsp"); 24 | 25 | // Analogue Synth 26 | 27 | voice(gate, gain, pitch) = (lfo1, lfo2) <: (_,_,osc1,osc2,noisegen) 28 | : (_,_,pre_filter_mix) // l1, l2, f1_in, f2_in 29 | // to filters 30 | <: ((_,_,!,_), ((_,!,_,!) : filter1)) // l1, l2, f2_in, filter1, filter1_to_f2 31 | <: ((_,!,!,_,!), (!,_,!,!,!), ((!,_,_,!,_) : (_,_+_) : filter2)) // l1, f1_out, l2, f2_out 32 | // to amps 33 | : (amp1, amp2) 34 | with { 35 | lfo1 = oscillators.lfo1(gate); 36 | lfo2 = oscillators.lfo2(gate); 37 | osc1 = oscillators.osc1(pitch); 38 | osc2 = oscillators.osc2(pitch); 39 | noisegen = oscillators.noisegen; 40 | filter1 = filters.filter1(gate, pitch); 41 | filter2 = filters.filter2(gate, pitch); 42 | amp1 = amps.amp1(gate, gain, pitch); 43 | amp2 = amps.amp2(gate, gain, pitch); 44 | 45 | // in : o11, o12, o21, o22, n1, n2 46 | // out : f1_in, f2_in 47 | pre_filter_mix = bus6 <: (((_,!,_,!,_,!) : _+_+_), ((!,_,!,_,!,_) : _+_+_)); 48 | 49 | }; 50 | 51 | main_out = nentry("/h:amp/output", 1, 0, 1, 0.01); // TODO in dB 52 | 53 | process = voice(mono_gate, mono_gain, mono_pitch) : effects :> (main_out * _, main_out * _); 54 | 55 | -------------------------------------------------------------------------------- /faust/dynamic.dsp: -------------------------------------------------------------------------------- 1 | 2 | 3 | process = select2(_, 0, 1); 4 | -------------------------------------------------------------------------------- /faust/effects.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("effect.lib"); 16 | import("oscillator.lib"); 17 | import("music.lib"); 18 | import("filter.lib"); 19 | import("freeverb.dsp"); 20 | 21 | import("utils.dsp"); 22 | 23 | // chorus & flanger 24 | 25 | flanger_effect = vgroup("flanger", bypass2(bp, bus2 <: (bus2, flanger_stereo(dmax,curdel1,curdel2,depth,fb,invert)) : mix2_stereo(mix))) 26 | with { 27 | // parameters 28 | bp = checkbox("bypass"); 29 | invert = checkbox("invert"); 30 | freq = hslider("speed", 0.5, 0, 10, 0.01); // Hz 31 | depth = 1.0; 32 | //depth = hslider("depth", 1, 0, 1, 0.001); 33 | fb = hslider("feedback", 0, -0.999, 0.999, 0.01); 34 | //level = hslider("output_level", 0, -60, 10, 0.1) : db2linear; // dB 35 | mix = hslider("mix", 0.5, 0, 1, 0.01); 36 | 37 | dmax = 2048; 38 | dflange = 0.001 * SR * hslider("flange_delay", 10, 0, 20, 0.01); // ms 39 | //odflange = 0.001 * SR * hslider("delay_offset", 1, 0, 20, 0.001); // ms 40 | odflange = 0.0; 41 | curdel1 = odflange + dflange * (1 + oscrs(freq))/2; // sine for left 42 | curdel2 = odflange + dflange * (1 + oscrc(freq))/2; // cosine for right 43 | }; 44 | 45 | //delay 46 | 47 | delay_effect = vgroup("delay", bypass2(bp, bus2 <: (bus2, stereo_delay) : mix2_stereo(mix))) 48 | with { 49 | bp = checkbox("bypass"); 50 | length = 0.001 * SR * hslider("length", 10, 0, 1000, 1); // ms 51 | cutoff = hslider("cutoff", 200, 0, 10000, 10); 52 | depth = hslider("depth", 0.5, 0, 1, 0.01); 53 | lp_delay = lowpass(2,cutoff) : delay(SR,length); 54 | stereo_delay = bus2 : (((depth*_,depth*_,_,_) :> bus2) ~ (lp_delay, lp_delay)); 55 | mix = hslider("mix", 0.5, 0, 1, 0.01); 56 | }; 57 | 58 | // reverb 59 | 60 | // freeverb based 61 | reverb_effect = vgroup("reverb", bypass2(bp, fxctrl(fixedgain, mix, stereoReverb(combfeed, allpassfeed, dampSlider, stereospread)))) 62 | with { 63 | bp = checkbox("bypass"); 64 | dampSlider = hslider("damp",0.720, 0, 1, 0.025) * scaledamp; 65 | roomsizeSlider = hslider("roomSize", 0.540, 0, 1, 0.025) * scaleroom + offsetroom; 66 | combfeed = roomsizeSlider; 67 | mix = hslider("mix", 0.141, 0, 1, 0.025); 68 | }; 69 | 70 | 71 | // topologies 72 | // A - B - C 73 | // B - A - C 74 | // A/B - C 75 | // B/A - C 76 | 77 | effects = vgroup("effects", bus4 :> bus2 : flanger_effect : delay_effect : reverb_effect); 78 | 79 | 80 | -------------------------------------------------------------------------------- /faust/filters.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | import("effect.lib"); 15 | 16 | import("filter.lib"); 17 | 18 | import("utils.dsp"); 19 | 20 | // filters 21 | 22 | // in : lfo, signal 23 | filter1(gate, pitch) = vgroup("filter1", (_,(gate : env),_) : filter(pitch) <: (_, to_f2 * _) ) 24 | with { 25 | to_f2 = hslider("to_f2",0,0,1,0.01); 26 | }; 27 | 28 | // in : lfo, signal 29 | filter2(gate, pitch) = vgroup("filter2", (_,(gate : env),_) : filter(pitch) ); 30 | 31 | filter(pitch, lfo, env) = bypass1(checkbox("bypass"), reson_filter( 32 | type, 33 | key2hz(cutoff, kbd_track * (pitch - A4) + (lfo_to_f * lfo) + (env_to_f * env)), 34 | q + (lfo_to_q * lfo) + (env_to_q * env))) 35 | with { 36 | type = hslider("type", 0, 0, 3, 1); 37 | cutoff = hslider("cutoff", 440, 0, 5000, 10); 38 | kbd_track = hslider("kbd", 1, -12, 12, 0.1); 39 | lfo_to_f = hslider("lfo_to_f",0,-12,12,0.1); 40 | env_to_f = hslider("env_to_f",0,-12,12,0.1); 41 | q = hslider("q",0.5,0,10,0.01); 42 | lfo_to_q = hslider("lfo_to_q",0,-1,1,0.1); 43 | env_to_q = hslider("env_to_q",0,-1,1,0.1); 44 | }; 45 | 46 | // helpers 47 | 48 | reson_filter(type, freq, res) = _ <: select4(type, 49 | resonlp(freq, res, 1.0), // lowpass 50 | resonhp(freq, res, 1.0), // highpass 51 | resonbp(freq, res, 1.0), // bandpass 52 | resonbr(freq, res, 1.0)) // bandreject 53 | with { 54 | 55 | resonbr(fc,Q,gain,x) = (gain * x) - resonbp(fc,Q,gain,x); 56 | 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /faust/freeverb.dsp: -------------------------------------------------------------------------------- 1 | declare name "freeverb"; 2 | declare version "1.0"; 3 | declare author "Grame"; 4 | declare license "BSD"; 5 | declare copyright "(c)GRAME 2006"; 6 | 7 | //====================================================== 8 | // 9 | // Freeverb 10 | // Faster version using fixed delays (20% gain) 11 | // 12 | //====================================================== 13 | 14 | 15 | // Constant Parameters 16 | //-------------------- 17 | 18 | fixedgain = 0.015; 19 | scalewet = 3.0; 20 | scaledry = 2.0; 21 | scaledamp = 0.4; 22 | scaleroom = 0.28; 23 | offsetroom = 0.7; 24 | initialroom = 0.5; 25 | initialdamp = 0.5; 26 | initialwet = 1.0/scalewet; 27 | initialdry = 0; 28 | initialwidth= 1.0; 29 | initialmode = 0.0; 30 | freezemode = 0.5; 31 | stereospread= 23; 32 | allpassfeed = 0.5; 33 | 34 | 35 | // Filter Parametres 36 | //------------------ 37 | 38 | combtuningL1 = 1116; 39 | combtuningL2 = 1188; 40 | combtuningL3 = 1277; 41 | combtuningL4 = 1356; 42 | combtuningL5 = 1422; 43 | combtuningL6 = 1491; 44 | combtuningL7 = 1557; 45 | combtuningL8 = 1617; 46 | 47 | allpasstuningL1 = 556; 48 | allpasstuningL2 = 441; 49 | allpasstuningL3 = 341; 50 | allpasstuningL4 = 225; 51 | 52 | 53 | // Control Sliders 54 | //-------------------- 55 | // Damp : filtrage des aigus des echos (surtout actif pour des grandes valeurs de RoomSize) 56 | // RoomSize : taille de la piece 57 | // Dry : signal original 58 | // Wet : signal avec reverbration 59 | 60 | dampSlider = hslider("Damp",0.720, 0, 1, 0.025)*scaledamp; 61 | roomsizeSlider = hslider("RoomSize", 0.540, 0, 1, 0.025)*scaleroom + offsetroom; 62 | wetSlider = hslider("Wet", 0.141, 0, 1, 0.025); 63 | drySlider = hslider("Dry", 0, 0, 1, 0.025); 64 | combfeed = roomsizeSlider; 65 | 66 | 67 | 68 | 69 | 70 | // Comb and Allpass filters 71 | //------------------------- 72 | 73 | allpass(dt,fb) = (_,_ <: (*(fb),_:+:@(dt)), -) ~ _ : (!,_); 74 | 75 | comb(dt, fb, damp) = (+:@(dt)) ~ (*(1-damp) : (+ ~ *(damp)) : *(fb)); 76 | 77 | 78 | // Reverb components 79 | //------------------ 80 | 81 | monoReverb(fb1, fb2, damp, spread) 82 | = _ <: comb(combtuningL1+spread, fb1, damp), 83 | comb(combtuningL2+spread, fb1, damp), 84 | comb(combtuningL3+spread, fb1, damp), 85 | comb(combtuningL4+spread, fb1, damp), 86 | comb(combtuningL5+spread, fb1, damp), 87 | comb(combtuningL6+spread, fb1, damp), 88 | comb(combtuningL7+spread, fb1, damp), 89 | comb(combtuningL8+spread, fb1, damp) 90 | +> 91 | allpass (allpasstuningL1+spread, fb2) 92 | : allpass (allpasstuningL2+spread, fb2) 93 | : allpass (allpasstuningL3+spread, fb2) 94 | : allpass (allpasstuningL4+spread, fb2) 95 | ; 96 | 97 | stereoReverb(fb1, fb2, damp, spread) 98 | = + <: monoReverb(fb1, fb2, damp, 0), monoReverb(fb1, fb2, damp, spread); 99 | 100 | 101 | // fxctrl : add an input gain and a wet-dry control to a stereo FX 102 | //---------------------------------------------------------------- 103 | 104 | fxctrl(g,w,Fx) = _,_ <: (*(g),*(g) : Fx : *(w),*(w)), *(1-w), *(1-w) +> _,_; 105 | 106 | 107 | 108 | // Freeverb 109 | //--------- 110 | 111 | freeverb = vgroup("Freeverb", fxctrl(fixedgain, wetSlider, stereoReverb(combfeed, allpassfeed, dampSlider, stereospread))); 112 | 113 | //process = freeverb; 114 | -------------------------------------------------------------------------------- /faust/midi.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | // MIDI 16 | 17 | mono_pitch = hslider("/h:midi/pitch", 64, 32, 100, 1); 18 | 19 | mono_gain = hslider("/h:midi/gain", 1, 0, 1, 0.01); 20 | 21 | mono_gate = button("/h:midi/gate"); 22 | 23 | 24 | -------------------------------------------------------------------------------- /faust/oscdemo.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("midi.dsp"); 16 | filters = library("filters.dsp"); 17 | oscillators = library("oscillators.dsp"); 18 | amps = library("amps.dsp"); 19 | 20 | import("utils.dsp"); 21 | 22 | // Simplified version for testing 23 | 24 | // process 25 | 26 | process = hgroup("simple", lfo1 : osc1 : (_+_)) 27 | with { 28 | lfo1 = oscillators.lfo1(mono_gate); 29 | osc1 = oscillators.osc1(mono_pitch); 30 | }; 31 | 32 | 33 | -------------------------------------------------------------------------------- /faust/oscillators.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("oscillator.lib"); 16 | import("music.lib"); 17 | 18 | import("midi.dsp"); 19 | import("utils.dsp"); 20 | 21 | // oscillators 22 | 23 | // in : gate 24 | lfo1 = vgroup("lfo1", select2(checkbox("power"), 0, lfo)); 25 | 26 | // in : gate 27 | lfo2 = vgroup("lfo2", select2(checkbox("power"), 0, lfo)); 28 | 29 | lfo(gate) = oscillator(type, freq, width) : fade_in(fade_in_samples, gate) : delay(SR, delay_in_samples) 30 | with { 31 | type = hslider("type", 0, 0, 4, 1); 32 | freq = hslider("freq", 1, 1, 50, 1); 33 | width = hslider("width", 0.5, 0.0, 1.0, 0.01); 34 | fade_in_samples = hslider("fade_in", 0, 0, 5, 0.01) * SR; 35 | delay_in_samples = hslider("delay", 0, 0, 1, 0.01) * SR; 36 | }; 37 | 38 | 39 | // in : pitch, lfo 40 | osc1 = vgroup("osc1", multiselect(2, checkbox("power"), 0, 0, osc_)); 41 | 42 | // in : pitch, lfo 43 | osc2 = vgroup("osc2", multiselect(2, checkbox("power"), 0, 0, osc_)); 44 | 45 | osc_(pitch, lfo) = oscillator( 46 | type, 47 | key2hz(440.0, kbd_track * (pitch - A4) + tune + finetune + (lfo_to_p * lfo)), 48 | width + lfo_to_w * lfo : normalize(0,1)) * level 49 | : split(f1_to_f2) 50 | with { 51 | type = hslider("type", 0, 0, 4, 1); 52 | kbd_track = hslider("kbd", 1, -12, 12, 0.1); 53 | tune = hslider("tune", 0, -24, 24, 1); 54 | finetune = hslider("finetune", 0, -1, 1, 0.01); 55 | lfo_to_p = hslider("lfo_to_p", 0, -12, 12, 0.1); 56 | width = hslider("width", 0.5, 0.0, 1.0, 0.01); 57 | lfo_to_w = hslider("lfo_to_w", 0, -0.5, 0.5, 0.01); 58 | level = hslider("level", 0.5, 0, 1, 0.01); 59 | f1_to_f2 = hslider("f1_to_f2", 0, 0, 1, 0.01); 60 | }; 61 | 62 | // noise 63 | 64 | noisegen = vgroup("noise", multiselect(2, checkbox("power"), 0, 0, noise 65 | : lowpass(1, noise_color) * noise_level 66 | : split(f1_to_f2))) 67 | with { 68 | noise_color = hslider("color", 2000, 200, 5000, 50); 69 | noise_level = hslider("level", 0, 0, 1, 0.01); 70 | f1_to_f2 = hslider("f1_to_f2", 0, 0, 1, 0.01); 71 | }; 72 | 73 | // helpers 74 | 75 | oscillator(type, freq, width) = select5(type, 76 | osc(freq), 77 | triangle(freq), 78 | sawtooth(freq), 79 | squarewave(freq, width), 80 | random) 81 | with { 82 | 83 | squarewave(freq, width) = 2 * pulsetrainpos(freq, width) - 1; 84 | 85 | triangle(freq) = saw1(freq) : abs : (_*2-1); 86 | 87 | random = noise; // TODO : improve 88 | 89 | }; 90 | 91 | //process = osc1(0) : (gate * gain*_, gate * gain*_); 92 | 93 | -------------------------------------------------------------------------------- /faust/simple.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | import("midi.dsp"); 16 | filters = library("filters.dsp"); 17 | oscillators = library("oscillators.dsp"); 18 | amps = library("amps.dsp"); 19 | import("utils.dsp"); 20 | 21 | // Simplified version for testing 22 | 23 | // process 24 | 25 | // LFO > OSC > FILTER > AMP 26 | process = hgroup("simple", lfo1 <: (_,osc1) : (_,_+_) <: (_,!,filter1) : (_,_,!) : amp1) 27 | with { 28 | lfo1 = oscillators.lfo1(mono_gate); 29 | osc1 = oscillators.osc1(mono_pitch); 30 | filter1 = filters.filter1(mono_gate, mono_pitch); 31 | amp1 = amps.amp1(mono_gate, mono_gain, mono_pitch); 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /faust/standalone-poly.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | analogue = library("analogue-poly.dsp"); 16 | 17 | // process 18 | 19 | process = hgroup("analogue", analogue.process); 20 | -------------------------------------------------------------------------------- /faust/standalone.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | analogue = library("analogue.dsp"); 16 | 17 | // process 18 | 19 | process = hgroup("analogue", analogue.process); 20 | -------------------------------------------------------------------------------- /faust/test.dsp: -------------------------------------------------------------------------------- 1 | //import("effect.lib"); 2 | import("filter.lib"); 3 | import("utils.dsp"); 4 | import("math.lib"); 5 | 6 | // FILTERS 7 | 8 | // reference 9 | moog_vcf(res,fr) = (+ : seq(i,4,pole(p)) : *(unitygain(p))) ~ *(mk) 10 | with { 11 | p = 1.0 - fr * 2.0 * PI / SR; // good approximation for fr << SR 12 | unitygain(p) = pow(1.0-p,4.0); // one-pole unity-gain scaling 13 | mk = -4.0 * max(0,min(res,0.999999)); // need mk > -4 for stability 14 | }; 15 | 16 | // by Victor Lazzarini 17 | moogladder(f,res) = filter(f,res) : aver 18 | with { 19 | v2 = 40000; 20 | fcor(f) = 1.8730*(f^3) + 0.4955*(f^2) - 0.6490*f + 0.9988; 21 | acor(f) = -3.9364*(f^2) + 1.8409*f + 0.9968; 22 | vg2(f) = v2*(1 - exp(-2*PI*fcor(f/(SR/2))*f/(SR))); 23 | sec(f) = (/(v2) : tanh : *(vg2(f))) : + ~ (_ <: _, (/(v2) : tanh : *(vg2(f)) : *(-1)): + ); 24 | filter(f,res) = (+ : sec(f) : sec(f) : sec(f) : sec(f)) ~ (*(4*res*acor(f/(SR/2))) :*(-1)); 25 | aver(x) = 0.5*(x + x'); 26 | }; 27 | 28 | // Moog Ladder Filter 29 | // 30 | // Reference : New Approaches to Digital Subtractive Synthesis 31 | // Antti Huovilainen and Vesa Välimäki 32 | reson_filter(type, freq, res, dist_amount, drive) = filter : mix 33 | with { 34 | 35 | filter(x) = (x+_ <: (lp,_) <: (lp,!,_,_) <: (lp,!,!,_,_,_) <: (lp,!,!,!,_,_,_,_)) ~ (distort : ((_-comp*x)*mk)); 36 | comp = 0.5; 37 | lp = (_*1.3) : zero(-0.3) : (_*g) : pole(1-g); 38 | g = 1.0 - exp(-2.0 * PI * freq / SR); 39 | mk = -4.0 * max(0, min(res,0.999999)); // need mk > -4 for stability 40 | 41 | distort = _ <: mix2(dist_amount, _, tanh(drive * _)); 42 | 43 | mix(db0, db6, db12, db18, db24) = select8(type, db24, db18, db12, db6, 44 | db0 - db24, // hp 45 | db24 - db12, // bp12 46 | db18 - db24, // bp18/6 47 | (db18 - db24) + 2/3*db0); // notch 48 | 49 | }; 50 | 51 | // Moog Ladder Filter 52 | // Digital Sound Generation - Beat Frei 53 | 54 | process = reson_filter(0, 440, 1, 0, 0, 0.5); 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /faust/test2.dsp: -------------------------------------------------------------------------------- 1 | // 2 | import("math.lib"); 3 | osclib = library("oscillator.lib"); 4 | import("utils.dsp"); 5 | 6 | process = mix2(mix, oscillator_old(type, freq, width), dpw_oscillator(type, freq, width)) : (gain*_) <: (_,_) 7 | with { 8 | mix = hslider("mix", 0.5, 0, 1, 0.1); 9 | type = hslider("type", 0, 0, 4, 1); 10 | freq = hslider("freq", 440, 10, 10000, 10); 11 | width = hslider("width", 0.5, 0.0, 1.0, 0.1); 12 | gain = hslider("gain", 0.5, 0, 1, 0.1); 13 | }; 14 | 15 | // OLD 16 | 17 | oscillator_old(type, freq, width) = select5(type, 18 | osclib.osc(freq), 19 | triangle(freq), 20 | osclib.saw1(freq), 21 | squarewave(freq, width), 22 | random) 23 | with { 24 | 25 | squarewave(freq, width) = 2.0 * osclib.pulsetrainpos(freq, width) - 1.0; 26 | 27 | triangle(freq) = osclib.saw1(freq) : abs : (_*2.0-1.0); 28 | 29 | random = osclib.noise; // TODO : improve 30 | 31 | }; 32 | 33 | // DPW 34 | 35 | // saw2(freq) = saw1(freq) <: * <: -(mem) : *(0.25'*SR/freq); 36 | 37 | dpw_oscillator(type, freq, width) = phase(freq) <: select2(type > 0, sin(2*PI*_), dpw) 38 | with { 39 | 40 | dpw = bi : shape <: -(mem) : scale : (SR/freq'*_); 41 | 42 | // type tri saw square 43 | shape(x) = select3(type-1, x-x*abs(x), x*x, 0); 44 | scale = select3(type-1, 0.5, 0.25, 1)*_; 45 | 46 | }; 47 | 48 | // PHASE SHAPING OSCILLATORS 49 | 50 | oscillator(type, freq, width) = phase(freq) : phase_to_osc(type, width); 51 | 52 | oscillator_slave(type, freq, width, a1) = phase(freq) : (a1*_) : mod1 : phase_to_osc(type, width); 53 | 54 | phase(freq) = (+(q) : mod1) ~ _ 55 | with { 56 | q = float(freq)/float(SR); 57 | }; 58 | 59 | // oscillators should be stateless : no recursion, no delays 60 | phase_to_osc(type, width) = _ <: select5(type, 61 | sin(2*PI*_), // TODO : optimize 62 | tri, 63 | saw, 64 | square(width), 65 | osclib.noise); 66 | 67 | // square (pwm) 68 | square(w) = select2(_ < w, -1.0, 1.0); 69 | 70 | saw = bi; 71 | 72 | tri = bi : fabs : bi; 73 | 74 | // PHASE SHAPERS 75 | 76 | // triangle 77 | 78 | gtri(a0, a1) = bi : fabs : glin(a0, a1) : mod1; 79 | 80 | gpulse(freq, w, x) = x - mod1(x + SR/freq) + w; 81 | 82 | // TODO 83 | //gvtri(w, a0, a1) = svtri(m) : glin(a0, a1) : mod1; 84 | 85 | gripple(m) = _ <: (_ + fmod(_,m)); 86 | 87 | mod1 = fmod(_, 1.0); 88 | 89 | glin(a0, a1) = a1*_ + a0; 90 | 91 | // unipolar to bipolar 92 | bi = 2.0*_ - 1.0; 93 | 94 | // bipolar to unipolar 95 | uni = 0.5*_ + 0.5; 96 | -------------------------------------------------------------------------------- /faust/utils.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 Timo Westkämper 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | music = library("music.lib"); 16 | 17 | // utilities 18 | 19 | split(ratio) = _ <: ((1-ratio) * _, ratio * _); 20 | 21 | // mix variant of select2 22 | mix2(ratio, a, b) = ratio * b + (1 - ratio) * a; 23 | 24 | mix2_stereo(ratio, al, ar, bl, br) = mix2(ratio, al, bl), mix2(ratio, ar, br); 25 | 26 | multiselect(n,s) = interleave(n,2) <: par(i,n, select2(s)); 27 | 28 | select4(i,a,b,c,d) = select2(i > 2, select3(i,a,b,c), d); 29 | 30 | select5(i,a,b,c,d,e) = select2(i > 3, select4(i,a,b,c,d), e); 31 | 32 | select6(i,a,b,c,d,e,f) = select2(i > 2, select3(i,a,b,c), select3(i-2,d,e,f)); 33 | 34 | select7(i,a,b,c,d,e,f,g) = select2(i > 3, select4(i,a,b,c,d), select3(i-3,e,f,g)); 35 | 36 | select8(i,a,b,c,d,e,f,g,h) = select2(i > 3, select4(i,a,b,c,d), select4(i-3,e,f,g,h)); 37 | 38 | fade_in(samples, gate) = select2(samples > 0, gate, fade(gate) ~ _) * _ 39 | with { 40 | fade(gate, x) = select2(x < 1, gate, x + (1/samples)); 41 | }; 42 | 43 | normalize(min_val,max_val) = max(min_val) : min(max_val); 44 | 45 | bpm = nentry("/h:main/bpm", 120, 40, 280, 1); 46 | 47 | A4 = 69.0; // 440 Hz 48 | 49 | key2hz(base_freq, x) = base_freq * pow(2.0, x / 12); 50 | 51 | env = music.adsr( 52 | hslider("attack", 0, 0, 2, 0.005), 53 | hslider("decay", 1, 0, 4, 0.01), 54 | hslider("sustain", 1, 0, 1, 0.01) * 100, 55 | hslider("release", 1, 0, 4, 0.01)); 56 | 57 | -------------------------------------------------------------------------------- /manifest.ttl: -------------------------------------------------------------------------------- 1 | @prefix lv2: . 2 | @prefix rdfs: . 3 | 4 | a lv2:Plugin; 5 | rdfs:seeAlso . 6 | -------------------------------------------------------------------------------- /portmeta.py: -------------------------------------------------------------------------------- 1 | import rdflib 2 | from rdflib.Graph import Graph 3 | 4 | # TODO : improve namespace usage 5 | rdf_type = rdflib.URIRef('http://www.w3.org/1999/02/22-rdf-syntax-ns#type') 6 | lv2_ControlPort = rdflib.URIRef('http://lv2plug.in/ns/lv2core#ControlPort') 7 | lv2_index = rdflib.URIRef('http://lv2plug.in/ns/lv2core#index') 8 | lv2_symbol = rdflib.URIRef('http://lv2plug.in/ns/lv2core#symbol') 9 | lv2_name = rdflib.URIRef('http://lv2plug.in/ns/lv2core#name') 10 | lv2_minimum = rdflib.URIRef('http://lv2plug.in/ns/lv2core#minimum') 11 | lv2_maximum = rdflib.URIRef('http://lv2plug.in/ns/lv2core#maximum') 12 | lv2_default = rdflib.URIRef('http://lv2plug.in/ns/lv2core#default') 13 | 14 | ext_step = rdflib.URIRef('http://www.westkamper.com/lv2/ext#step') 15 | 16 | meta_cpp = [] 17 | meta_cpp.append("#ifndef ANALOGUE_META") 18 | meta_cpp.append("#define ANALOGUE_META\n") 19 | 20 | meta_cpp.append("typedef struct {") 21 | meta_cpp.append(" const char *symbol;") 22 | meta_cpp.append(" const char *name;") 23 | meta_cpp.append(" float min;") 24 | meta_cpp.append(" float max;") 25 | meta_cpp.append(" float default_value;") 26 | meta_cpp.append(" float step;") 27 | meta_cpp.append("} port_meta_t;\n") 28 | 29 | meta_cpp.append("static const port_meta_t p_port_meta[] = {") 30 | 31 | g = Graph() 32 | g.parse("analogue.ttl", format="n3") 33 | maxIndex = 0 34 | 35 | for i in g.objects(None, lv2_index): 36 | maxIndex = max(maxIndex, i.toPython()) 37 | 38 | for i in range(3, maxIndex + 1): 39 | p = g.subjects(lv2_index, rdflib.Literal(i)).next() 40 | symbol = g.objects(p, lv2_symbol).next() 41 | name = g.objects(p, lv2_name).next() 42 | minimum = g.objects(p, lv2_minimum).next().toPython() 43 | maximum = g.objects(p, lv2_maximum).next().toPython() 44 | default = g.objects(p, lv2_default).next().toPython() 45 | step = g.objects(p, ext_step).next().toPython() 46 | 47 | meta_cpp.append(' {"%s", "%s", %s, %s, %s, %s},' % (symbol, name, minimum, maximum, default, step)) 48 | 49 | meta_cpp.append("};") 50 | meta_cpp.append("#endif") 51 | 52 | cppFile = open("gen/analogue-meta.h", "w") 53 | cppFile.write("\n".join(meta_cpp)) 54 | cppFile.close() 55 | 56 | -------------------------------------------------------------------------------- /src/analogue-common.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALOGUE_COMMON_H 2 | #define ANALOGUE_COMMON_H 3 | 4 | #define NOUTS 2 //number of outputs 5 | #define NVOICES 8 //max polyphony 6 | #define SILENCE 0.0001f //voice choking 7 | #define CONTROL_PORT_OFFSET 3 //number of non-control ports 8 | 9 | static float scale_midi_to_f(unsigned char data) { 10 | return 0.0078f * (float)data; 11 | } 12 | 13 | static float scale_pitchbend_to_f(unsigned char data1, unsigned char data2) { 14 | return 0.000121153f * (float)(data1 * 128 + data2 - 8254); 15 | } 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/analogue-gui-test.cpp: -------------------------------------------------------------------------------- 1 | #include "analogue-gui.cpp" 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | Gtk::Main kit(argc, argv); 6 | 7 | AnalogueGUI guiBox("http://www.westkamper.com/lv2/analogue/gui"); 8 | 9 | float controls[p_n_ports-3]; 10 | for (int i = 0; i < p_n_ports-3; i++) { 11 | controls[i] = p_port_meta[i].default_value; 12 | } 13 | 14 | Gtk::Window window; 15 | window.set_title("Analogue"); 16 | window.set_default_size(800, 400); 17 | window.add(guiBox); 18 | window.show_all(); 19 | 20 | Gtk::Main::run(window); 21 | 22 | return 0; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/analogue-gui.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "comboboxes.h" 5 | #include "knob.h" 6 | #include "toggle.h" 7 | #include "panel.h" 8 | #include "analogue.peg" 9 | #include "analogue-meta.h" 10 | 11 | #include 12 | #include 13 | 14 | using namespace sigc; 15 | using namespace Gtk; 16 | 17 | class AnalogueGUI : public LV2::GUI, LV2::WriteMIDI > { 18 | public: 19 | 20 | AnalogueGUI(const std::string& URI) { 21 | std::cout << "starting GUI" <set_size(30); 40 | knob->set_radius(10); 41 | } else if (isModControl(i) || isEffect(i)) { 42 | // medium 43 | knob->set_radius(12.0); 44 | } 45 | scales[i] = manage(knob); 46 | } 47 | } 48 | 49 | //connect widgets to control ports (change control values when sliders are moved) 50 | for (int i = 0; i < control_ports; i++) { 51 | slot slot1 = compose(bind<0>(mem_fun(*this, &AnalogueGUI::write_control), i + 3), 52 | mem_fun(*scales[i], &Changeable::get_value)); 53 | slot slot2 = compose(bind<0>(mem_fun(*this, &AnalogueGUI::change_status_bar), i + 3), 54 | mem_fun(*scales[i], &Changeable::get_value)); 55 | scales[i]->connect(slot1); 56 | if (!isOSCType(i) && !isFilterType(i) && !isToggle(i)) { 57 | scales[i]->connect(slot2); 58 | } 59 | } 60 | 61 | //connect all faders to the 'notify' function to inform the plugin to recalculate 62 | /*for (int i = 0; i < control_ports; i++) { 63 | scales[i]->signal_value_changed().connect( 64 | mem_fun(*this, &AnalogueGUI::notify_param_change)); 65 | }*/ 66 | 67 | Table* block1 = manage(new Table(2,4)); 68 | block1->attach(*createOSC1(), 0, 1, 1, 2); 69 | block1->attach(*createFilter1(), 1, 2, 1, 2); 70 | block1->attach(*createAmp1(), 2, 3, 1, 2); 71 | block1->attach(*createLFO1(), 3, 4, 1, 2); 72 | block1->attach(*createLFO2(), 0, 1, 2, 3); 73 | block1->attach(*createOSC2(), 1, 2, 2, 3); 74 | block1->attach(*createFilter2(), 2, 3, 2, 3); 75 | block1->attach(*createAmp2(), 3, 4, 2, 3); 76 | mainBox.pack_start(*align(block1)); 77 | 78 | HBox* block3 = manage(new HBox()); 79 | block3->pack_start(*createFilter1Env()); 80 | block3->pack_start(*createFilter2Env()); 81 | block3->pack_start(*createAmp1Env()); 82 | block3->pack_start(*createAmp2Env()); 83 | mainBox.pack_start(*align(block3)); 84 | 85 | HBox* block4 = manage(new HBox()); 86 | block4->pack_start(*createNoise()); 87 | block4->pack_start(*createFlanger()); 88 | block4->pack_start(*createDelay()); 89 | block4->pack_start(*createReverb()); 90 | mainBox.pack_start(*align(block4)); 91 | 92 | HBox* header = manage(new HBox()); 93 | header->pack_start(*manage(new Image("analogue.png"))); 94 | header->pack_end(*scales[p_amp_output - 3]->get_widget()); 95 | header->set_border_width(5); 96 | mainBox.pack_start(*align(header)); 97 | 98 | mainBox.pack_end(statusbar); 99 | 100 | add(*align(&mainBox)); 101 | 102 | std::cout << "GUI ready" <attach(*scales[port_index - 3]->get_widget(), left, left + 1, top, top + 1); 297 | table->attach(*manage(new Label(label)), left, left + 1, top + 1, top + 2); 298 | } 299 | 300 | Widget* smallFrame(const char* label, Table* content) { 301 | content->set_border_width(2); 302 | content->set_col_spacings(2); 303 | content->set_spacings(2); 304 | 305 | Frame* frame = manage(new Frame()); 306 | frame->set_label_align(0.0f, 0.0f); 307 | frame->set_border_width(5); 308 | frame->set_label(label); 309 | frame->add(*content); 310 | 311 | Alignment* alignment = manage(new Alignment(0.0, 0.0, 1.0, 0.0)); 312 | alignment->add(*frame); 313 | return alignment; 314 | } 315 | 316 | Widget* frame(const char* label, int toggle, Table* content) { 317 | content->set_border_width(2); 318 | content->set_col_spacings(5); 319 | content->set_spacings(2); 320 | 321 | Panel* panel = manage(new Panel(label, scales[toggle - 3]->get_widget(), content)); 322 | 323 | Alignment* alignment = manage(new Alignment(0.0, 0.0, 1.0, 0.0)); 324 | alignment->add(*panel); 325 | return alignment; 326 | } 327 | 328 | Alignment* align(Widget* widget) { 329 | Alignment* alignment = manage(new Alignment(0.0, 0.0, 0.0, 0.0)); 330 | alignment->add(*widget); 331 | return alignment; 332 | } 333 | 334 | bool isEffect(int i) { 335 | const char* symbol = p_port_meta[i].symbol; 336 | return strstr(symbol, "effects_"); 337 | } 338 | 339 | bool isToggle(int i) { 340 | const char* symbol = p_port_meta[i].symbol; 341 | return strstr(symbol, "_power") || strstr(symbol, "_bypass"); 342 | } 343 | 344 | bool isPower(int i) { 345 | const char* symbol = p_port_meta[i].symbol; 346 | return strstr(symbol, "_power"); 347 | } 348 | 349 | bool isBypass(int i) { 350 | const char* symbol = p_port_meta[i].symbol; 351 | return strstr(symbol, "_bypass"); 352 | } 353 | 354 | bool isOSCType(int i) { 355 | const char* symbol = p_port_meta[i].symbol; 356 | return (strstr(symbol, "osc") || strstr(symbol, "lfo")) && strstr(symbol, "_type"); 357 | } 358 | 359 | bool isFilterType(int i) { 360 | const char* symbol = p_port_meta[i].symbol; 361 | return strstr(symbol, "filter1_type") || strstr(symbol, "filter2_type"); 362 | } 363 | 364 | bool isEnvControl(int i) { 365 | const char* symbol = p_port_meta[i].symbol; 366 | return strstr(symbol, "_attack") || strstr(symbol, "_decay") || strstr(symbol, "_sustain") || strstr(symbol, "_release"); 367 | } 368 | 369 | bool isModControl(int i) { 370 | const char* symbol = p_port_meta[i].symbol; 371 | return strstr(symbol, "_kbd_") || strstr(symbol, "_lfo_") || strstr(symbol, "_env_"); 372 | } 373 | 374 | void port_event(uint32_t port, uint32_t buffer_size, uint32_t format, const void* buffer) { 375 | if (port > 2) { 376 | scales[port-3]->set_value(*static_cast(buffer)); 377 | } 378 | } 379 | 380 | void change_status_bar(uint32_t port, float value) { 381 | if (p_port_meta[port-3].step >= 1.0f) { 382 | sprintf(statusBarText, "%s = %3.0f", p_port_meta[port-3].symbol, value); 383 | } else { 384 | sprintf(statusBarText, "%s = %3.3f", p_port_meta[port-3].symbol, value); 385 | } 386 | statusbar.remove_all_messages(); 387 | statusbar.push(statusBarText); 388 | } 389 | 390 | protected: 391 | VBox mainBox; 392 | Statusbar statusbar; 393 | char statusBarText[100]; 394 | 395 | //Knob *scales[p_n_ports - 3]; 396 | Changeable *scales[p_n_ports - 3]; 397 | }; 398 | 399 | static int _ = AnalogueGUI::register_class("http://www.westkamper.com/lv2/analogue/gui"); 400 | 401 | -------------------------------------------------------------------------------- /src/analogue.cpp: -------------------------------------------------------------------------------- 1 | #include "analogue.h" 2 | #include 3 | #include 4 | 5 | Analogue::Analogue(double r) : LV2::Plugin >(p_n_ports) { 6 | //license notice 7 | std::cout << std::endl; 8 | std::cout << "Analogue v.0.1, Copyright (c) 2011 Timo Westkämper" << std::endl; 9 | std::cout << "This is free software, and you are welcome to redistribute it" << std::endl; 10 | std::cout << "under certain conditions; see LICENSE file for details." << std::endl; 11 | std::cout << std::endl; 12 | 13 | // TODO : presets 14 | 15 | rate = r; 16 | m_midi_input = 0; 17 | m_midi_type = Parent::uri_to_id(LV2_EVENT_URI, "http://lv2plug.in/ns/ext/midi#MidiEvent"); 18 | 19 | synthUI = new CollectorUI(); 20 | synthUI->setOutputs(outputs); 21 | 22 | synth = createDSP(); 23 | synth->init((int)r); 24 | synth->buildUserInterface(synthUI); 25 | 26 | // zones for MIDI data 27 | //pitchBend = synthUI->getZone("pitchBend"); 28 | //breathControl = synthUI->getZone("breathControl"); 29 | 30 | char buffer[32]; 31 | for (int i = 0; i < NVOICES; i++) { 32 | sprintf(buffer, "midi_pitch%d", i); 33 | pitch[i] = synthUI->getZone(buffer); 34 | sprintf(buffer, "midi_gain%d", i); 35 | gain[i] = synthUI->getZone(buffer); 36 | sprintf(buffer, "midi_gate%d", i); 37 | gate[i] = synthUI->getZone(buffer); 38 | } 39 | 40 | // zones for control ports 41 | for (int i = 0; i < p_n_ports - 3; i++) { 42 | zones[i] = synthUI->getZone(p_port_meta[i].symbol); 43 | if (zones[i] == 0) { 44 | // TODO Exception 45 | std::cout << "No zone for " << p_port_meta[i].symbol << std::endl; 46 | } 47 | } 48 | 49 | std::cout << "ready" <compute(to - from, 0, outputs); 115 | } 116 | 117 | void Analogue::run(uint32_t sample_count) { 118 | LV2_Event_Iterator iter; 119 | lv2_event_begin(&iter, p < LV2_Event_Buffer>(m_midi_input)); 120 | 121 | uint8_t* event_data; 122 | uint32_t samples_done = 0; 123 | 124 | while (samples_done < sample_count) { 125 | uint32_t to = sample_count; 126 | LV2_Event* ev = 0; 127 | if (lv2_event_is_valid(&iter)) { 128 | ev = lv2_event_get(&iter, &event_data); 129 | to = ev->frames; 130 | lv2_event_increment(&iter); 131 | } 132 | 133 | if (to > samples_done) { 134 | render(samples_done, to); 135 | samples_done = to; 136 | } 137 | 138 | /* This is what we do with events: 139 | - if it's a MIDI event, pass it to handle_midi() 140 | - if it's something else, just ignore it (it's safe) 141 | */ 142 | if (ev) { 143 | if (ev->type == m_midi_type) { 144 | handle_midi(ev->size, event_data); 145 | } 146 | } 147 | } 148 | 149 | } 150 | 151 | void Analogue::handle_midi(uint32_t size, unsigned char* data) { 152 | //discard invalid midi messages 153 | if (size < 2) { 154 | return; 155 | } 156 | 157 | //receive on all channels 158 | switch(data[0] & 0xf0) { 159 | 160 | //note off 161 | case 0x80: { 162 | //discard invalid midi messages 163 | if (size != 3) { 164 | return; 165 | } 166 | off(data[1], data[2]); 167 | } 168 | break; 169 | 170 | //note on 171 | case 0x90: { 172 | //discard invalid midi messages 173 | if (size != 3) { 174 | return; 175 | } 176 | on(data[1], data[2]); 177 | } 178 | break; 179 | 180 | //pitch bend 181 | case 0xE0: { 182 | //discard invalid midi messages 183 | if (size != 3) { 184 | return; 185 | } 186 | 187 | setPitchBend(scale_pitchbend_to_f(data[1], data[2])); 188 | } 189 | break; 190 | 191 | case 0xB0: //controller 192 | //WIP: control preset parameters with assigned controllers 193 | { 194 | /*signed char param_id = -1; 195 | param_id = get_param_id_from_controller(data[1]); 196 | if (param_id >= 0) { 197 | float new_value = scale_midi_to_f(data[2]); 198 | setParameter(param_id, new_value); 199 | }*/ 200 | } 201 | 202 | // standard controller stuff 203 | switch(data[1]) 204 | { 205 | //mod wheel 206 | case 0x01: 207 | //discard invalid midi messages 208 | if (size != 3) { 209 | return; 210 | } 211 | //scale the mod value to cover the range [0..1] 212 | // DO NOTHING 213 | std::cout << "mod " << (int)data[2] << std::endl; 214 | break; 215 | 216 | // breath 217 | case 0x02: 218 | //discard invalid midi messages 219 | if (size != 3) { 220 | return; 221 | } 222 | setBreathControl(scale_midi_to_f(data[2])); 223 | break; 224 | 225 | //volume 226 | case 0x07: 227 | //discard invalid midi messages 228 | if (size != 3) { 229 | return; 230 | } 231 | 232 | setVolumeControl(scale_midi_to_f(data[2])); 233 | break; 234 | 235 | default: 236 | // TODO 237 | break; 238 | } 239 | break; 240 | 241 | default: 242 | break; 243 | } 244 | } 245 | 246 | static int _ = Analogue::register_class(p_uri); 247 | -------------------------------------------------------------------------------- /src/analogue.h: -------------------------------------------------------------------------------- 1 | #ifndef ANALOGUE_H 2 | #define ANALOGUE_H 3 | //See associated .cpp file for copyright and other info 4 | 5 | #include 6 | #include 7 | 8 | #include "analogue-common.h" 9 | #include "analogue.peg" 10 | #include "analogue-meta.h" 11 | 12 | #include "dsp.h" 13 | #include "collector-ui.h" 14 | 15 | class Analogue : public LV2::Plugin > { 16 | private: 17 | typedef LV2::Plugin > Parent; 18 | 19 | float rate; 20 | float *outputs[2]; 21 | 22 | float* pitch[NVOICES]; 23 | float* gain[NVOICES]; 24 | float* gate[NVOICES]; 25 | //float* pitchBend; 26 | //float* breathControl; 27 | 28 | float *zones[p_n_ports-3]; 29 | 30 | dsp *synth; 31 | CollectorUI* synthUI; 32 | 33 | protected: 34 | 35 | uint32_t m_midi_input; 36 | uint32_t m_midi_type; 37 | 38 | template T*& p(uint32_t port) { 39 | return reinterpret_cast(Parent::m_ports[port]); 40 | } 41 | 42 | float*& p(uint32_t port) { 43 | return reinterpret_cast(Parent::m_ports[port]); 44 | } 45 | 46 | 47 | public: 48 | Analogue(double rate); 49 | ~Analogue(); 50 | 51 | void handle_midi(uint32_t size, unsigned char* data); 52 | void setPitchBend(float value); 53 | void setBreathControl(float value); 54 | void setVolumeControl(float value); 55 | void run(uint32_t sample_count); 56 | 57 | void on(unsigned char key, unsigned char velo); 58 | void off(unsigned char key, unsigned char velo); 59 | void render(uint32_t from, uint32_t to); 60 | }; 61 | #endif 62 | -------------------------------------------------------------------------------- /src/changeable.h: -------------------------------------------------------------------------------- 1 | #ifndef CHANGEABLE_H 2 | #define CHANGEABLE_H 3 | 4 | #include 5 | #include 6 | 7 | class Changeable { 8 | public: 9 | 10 | virtual float get_value() = 0; 11 | 12 | virtual void set_value(float val) = 0; 13 | 14 | virtual void connect(sigc::slot slot) = 0; 15 | 16 | // TODO : is this necessary or should we use inheritance instance? 17 | virtual Gtk::Widget* get_widget() = 0; 18 | 19 | }; 20 | 21 | #endif //CHANGEABLE_H 22 | -------------------------------------------------------------------------------- /src/collector-ui.h: -------------------------------------------------------------------------------- 1 | #ifndef COLLECTOR_UI_H 2 | #define COLLECTOR_UI_H 3 | 4 | #include "dsp.h" 5 | 6 | #include 7 | #include 8 | //#include 9 | 10 | class CollectorUI : public UI { 11 | 12 | public: 13 | 14 | CollectorUI(){ 15 | boxIndex = 0; 16 | inputs = 0; 17 | outputs = 0; 18 | } 19 | 20 | virtual void addButton(const char* label, float* zone) { 21 | addZone(label, zone); 22 | } 23 | 24 | virtual void addToggleButton(const char* label, float* zone) { 25 | addZone(label, zone); 26 | } 27 | 28 | virtual void addCheckButton(const char* label, float* zone) { 29 | addZone(label, zone); 30 | } 31 | 32 | virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) { 33 | addZone(label, zone); 34 | } 35 | 36 | virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) { 37 | addZone(label, zone); 38 | } 39 | 40 | virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) { 41 | addZone(label, zone); 42 | } 43 | 44 | virtual void addNumDisplay(const char* label, float* zone, int precision) { 45 | addZone(label, zone); 46 | } 47 | 48 | virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) { 49 | addZone(label, zone); 50 | } 51 | 52 | virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { 53 | addZone(label, zone); 54 | } 55 | 56 | virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { 57 | addZone(label, zone); 58 | } 59 | 60 | virtual void declare(float*, const char*, const char*) { } 61 | 62 | virtual void openFrameBox(const char* label) { 63 | openBox(label); 64 | } 65 | 66 | virtual void openTabBox(const char* label) { 67 | openBox(label); 68 | } 69 | 70 | virtual void openHorizontalBox(const char* label) { 71 | openBox(label); 72 | } 73 | 74 | virtual void openVerticalBox(const char* label) { 75 | openBox(label); 76 | } 77 | 78 | virtual void closeBox() { 79 | boxIndex--; 80 | } 81 | 82 | virtual void show() { } 83 | 84 | virtual void run() { } 85 | 86 | float** getInputs() { 87 | return inputs; 88 | } 89 | 90 | float** getOutputs() { 91 | return outputs; 92 | } 93 | 94 | void setInputs(float** i) { 95 | inputs = i; 96 | } 97 | 98 | void setOutputs(float** o) { 99 | outputs = o; 100 | } 101 | 102 | float* getZone(std::string name) { 103 | return labelToZone[name]; 104 | } 105 | 106 | private: 107 | 108 | float** inputs; 109 | float** outputs; 110 | int boxIndex; 111 | const char* boxes[5]; 112 | 113 | std::map labelToZone; 114 | 115 | void addZone(const char* label, float* zone) { 116 | char fullPath[50]; 117 | strcpy(fullPath, boxes[1]); 118 | strcat(fullPath, "_"); 119 | for (int i = 2; i < boxIndex; i++) { 120 | strcat(fullPath, boxes[i]); 121 | strcat(fullPath, "_"); 122 | } 123 | strcat(fullPath, label); 124 | //std::cout << fullPath << std::endl; 125 | 126 | std::string name(fullPath); 127 | labelToZone[name] = zone; 128 | } 129 | 130 | void openBox(const char* label) { 131 | boxes[boxIndex++] = label; 132 | } 133 | 134 | }; 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /src/comboboxes-test.cpp: -------------------------------------------------------------------------------- 1 | #include "comboboxes.h" 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | Gtk::Main kit(argc, argv); 6 | 7 | //Knob knob(0.0, 1.0, 0.01); 8 | OSCTypeComboBox typeBox; 9 | typeBox.set_value(0.0f); 10 | 11 | Gtk::Window window; 12 | window.set_title("Analogue"); 13 | window.set_default_size(800, 400); 14 | window.add(typeBox); 15 | window.show_all(); 16 | 17 | Gtk::Main::run(window); 18 | 19 | return 0; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/comboboxes.h: -------------------------------------------------------------------------------- 1 | #ifndef COMBOBOXES_H 2 | #define COMBOBOXES_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "changeable.h" 9 | 10 | class SelectComboBox : public Gtk::EventBox, public Changeable { 11 | public: 12 | 13 | SelectComboBox(const char** labels, int count) : labels(labels), count(count){ 14 | add(label); 15 | // menu shown on button press 16 | signal_button_press_event().connect(sigc::mem_fun(*this, &SelectComboBox::on_button_press_event) ); 17 | 18 | // menu creation 19 | for (int i = 0; i < count; i++) { 20 | Gtk::MenuItem* menuItem = manage(new Gtk::MenuItem(labels[i])); 21 | menuItem->signal_activate().connect( 22 | sigc::bind(sigc::mem_fun(*this, &SelectComboBox::on_menu_selection), i)); 23 | menuPopup.append(*menuItem); 24 | } 25 | menuPopup.show_all(); 26 | set_value(0.0f); 27 | } 28 | 29 | bool on_button_press_event(GdkEventButton* event) { 30 | if(event->type == GDK_BUTTON_PRESS && event->button == 1) { 31 | menuPopup.popup(event->button, event->time); 32 | return true; 33 | } else { 34 | return false; 35 | } 36 | } 37 | 38 | void on_menu_selection(int i) { 39 | index = i; 40 | label.set_text(labels[index]); 41 | value_changed.emit(); 42 | } 43 | 44 | float get_value() { 45 | return (float)index; 46 | } 47 | 48 | void set_value(float val) { 49 | index = (int)val; 50 | label.set_text(labels[index]); 51 | } 52 | 53 | Gtk::Widget* get_widget() { 54 | return this; 55 | } 56 | 57 | void connect(sigc::slot s) { 58 | value_changed.connect(s); 59 | } 60 | 61 | private: 62 | const char** labels; 63 | int count; 64 | int index; 65 | 66 | Gtk::Menu menuPopup; 67 | Gtk::EventBox eventBox; 68 | Gtk::Label label; 69 | 70 | sigc::signal value_changed; 71 | 72 | }; 73 | 74 | const char* oscType[] = {"Sin", "Tri", "Saw", "Squ", "Rnd"}; 75 | 76 | const char* filterType[] = {"Low", "Hi", "Bnd", "Rej"}; 77 | 78 | // TODO : use generics here ?!? 79 | 80 | class OSCTypeComboBox : public SelectComboBox { 81 | public: 82 | OSCTypeComboBox() : SelectComboBox(oscType, 5) {} 83 | }; 84 | 85 | class FilterTypeComboBox : public SelectComboBox { 86 | public: 87 | FilterTypeComboBox() : SelectComboBox(filterType, 4) {} 88 | }; 89 | 90 | #endif //COMBOBOXES_H 91 | -------------------------------------------------------------------------------- /src/dsp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | float max(float x, float y) { 4 | return fmaxf(x,y); 5 | } 6 | 7 | float min(float x, float y) { 8 | return fminf(x,y); 9 | } 10 | 11 | 12 | #include "../gen/dsp.cpp" 13 | 14 | dsp *createDSP() { 15 | mydsp *ret = new mydsp(); 16 | return ret; 17 | } 18 | -------------------------------------------------------------------------------- /src/dsp.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Faust DSP headers and a function definition for a constructor 3 | **/ 4 | 5 | #ifndef _FAUST_DSP_H 6 | #define _FAUST_DSP_H 7 | 8 | 9 | class UI { 10 | public: 11 | UI() { } 12 | virtual ~UI() { } 13 | virtual void openFrameBox(const char* label) = 0; 14 | virtual void openTabBox(const char* label) = 0; 15 | virtual void openHorizontalBox(const char* label) = 0; 16 | virtual void openVerticalBox(const char* label) = 0; 17 | virtual void closeBox() = 0; 18 | virtual void addButton(const char* label, float* zone) = 0; 19 | virtual void addToggleButton(const char* label, float* zone) = 0; 20 | virtual void addCheckButton(const char* label, float* zone) = 0; 21 | virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0; 22 | virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) = 0; 23 | virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) = 0; 24 | virtual void addNumDisplay(const char* label, float* zone, int precision) = 0; 25 | virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) = 0; 26 | virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) = 0; 27 | virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) = 0; 28 | virtual void declare(float* , const char* , const char* ) {} 29 | }; 30 | 31 | class dsp { 32 | protected: 33 | int fSamplingFreq; 34 | public: 35 | dsp() {} 36 | virtual ~dsp() {} 37 | virtual int getNumInputs() = 0; 38 | virtual int getNumOutputs() = 0; 39 | virtual void buildUserInterface(UI* interface) = 0; 40 | virtual void init(int samplingRate) = 0; 41 | virtual void compute(int len, float** inputs, float** outputs) = 0; 42 | }; 43 | 44 | 45 | dsp *createDSP(); 46 | 47 | #endif /* _FAUST_DSP_H */ 48 | -------------------------------------------------------------------------------- /src/dump-rdf.h: -------------------------------------------------------------------------------- 1 | #ifndef DUMP_RDF_UI_H 2 | #define DUMP_RDF_UI_H 3 | 4 | #include "dsp.h" 5 | 6 | #include 7 | #include 8 | 9 | 10 | class DumpRDFUI : public UI { 11 | 12 | private: 13 | 14 | int counter; // first port index 15 | int boxIndex; 16 | const char* boxes[5]; 17 | 18 | void addZone(const char* label) { 19 | addZone(label, 1.0f, 0.0f, 0.0f, 1.0f); 20 | } 21 | 22 | void addZone(const char* label, float init, float min, float max, float step) { 23 | if (strcmp(boxes[1],"midi") == 0) return; 24 | 25 | char fullPath[50]; 26 | strcpy(fullPath, boxes[1]); 27 | strcat(fullPath, "_"); 28 | for (int i = 2; i < boxIndex; i++) { 29 | strcat(fullPath, boxes[i]); 30 | strcat(fullPath, "_"); 31 | } 32 | strcat(fullPath, label); 33 | 34 | printf(" [ a lv2:ControlPort, lv2:InputPort; lv2:index %d; lv2:symbol \"%s\"; lv2:name \"%s\";\n", counter++, fullPath, label); 35 | printf(" lv2:minimum %f; lv2:maximum %f; lv2:default %f; ext:step %f ],\n", min, max, init, step); 36 | puts(""); 37 | } 38 | 39 | void openBox(const char* label) { 40 | boxes[boxIndex++] = label; 41 | } 42 | 43 | public: 44 | 45 | DumpRDFUI() { 46 | counter = 3; 47 | boxIndex = 0; 48 | } 49 | 50 | virtual void addButton(const char* label, float* zone) { 51 | addZone(label); 52 | } 53 | 54 | virtual void addToggleButton(const char* label, float* zone) { 55 | addZone(label); 56 | } 57 | 58 | virtual void addCheckButton(const char* label, float* zone) { 59 | addZone(label); 60 | } 61 | 62 | virtual void addVerticalSlider(const char* label, float* zone, float init, float min, float max, float step) { 63 | addZone(label, init, min, max, step); 64 | } 65 | 66 | virtual void addHorizontalSlider(const char* label, float* zone, float init, float min, float max, float step) { 67 | addZone(label, init, min, max, step); 68 | } 69 | 70 | virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step) { 71 | addZone(label, init, min, max, step); 72 | } 73 | 74 | virtual void addNumDisplay(const char* label, float* zone, int precision) { 75 | //addZone(label); 76 | } 77 | 78 | virtual void addTextDisplay(const char* label, float* zone, const char* names[], float min, float max) { 79 | //addZone(label); 80 | } 81 | 82 | virtual void addHorizontalBargraph(const char* label, float* zone, float min, float max) { 83 | //addZone(label); 84 | } 85 | 86 | virtual void addVerticalBargraph(const char* label, float* zone, float min, float max) { 87 | //addZone(label); 88 | } 89 | 90 | virtual void declare(float*, const char*, const char*) { } 91 | 92 | virtual void openFrameBox(const char* label) { 93 | openBox(label); 94 | } 95 | 96 | virtual void openTabBox(const char* label) { 97 | openBox(label); 98 | } 99 | 100 | virtual void openHorizontalBox(const char* label) { 101 | openBox(label); 102 | } 103 | 104 | virtual void openVerticalBox(const char* label) { 105 | openBox(label); 106 | } 107 | 108 | virtual void closeBox() { 109 | boxIndex--; 110 | } 111 | 112 | virtual void show() { } 113 | 114 | virtual void run() { } 115 | 116 | }; 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /src/knob-test.cpp: -------------------------------------------------------------------------------- 1 | #include "knob.h" 2 | #include 3 | 4 | int main(int argc, char* argv[]) { 5 | Gtk::Main kit(argc, argv); 6 | 7 | Knob knob(0.0, 1.0, 0.01); 8 | 9 | Alignment alignment(0.0, 0.0, 0.0, 0.0)); 10 | alignmen.add(knob); 11 | 12 | Gtk::Window window; 13 | window.set_title("Analogue"); 14 | window.set_default_size(800, 400); 15 | window.add(alignment); 16 | window.show_all(); 17 | 18 | Gtk::Main::run(window); 19 | 20 | return 0; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/knob.h: -------------------------------------------------------------------------------- 1 | #ifndef KNOB_H 2 | #define KNOB_H 3 | 4 | // TODO : optimize imports 5 | #include 6 | #include // for cairo helper functions 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "changeable.h" 14 | 15 | using namespace Cairo; 16 | 17 | class Knob : public Gtk::DrawingArea, public Changeable { 18 | public: 19 | 20 | Knob(float min, float max, float step) : value(0.0), min(min), max(max), step(step) { 21 | set_size_request(40, 40); 22 | radius = 15.0; 23 | line_width = 2.5; 24 | range = max - min; 25 | sensitivity = range / step; 26 | //sensitivity = range / 100.0; 27 | 28 | add_events( Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON1_MOTION_MASK); 29 | signal_motion_notify_event().connect(mem_fun(this, &Knob::on_motion_notify)); 30 | signal_button_press_event().connect(mem_fun(this, &Knob::on_button_press)); 31 | } 32 | 33 | virtual ~Knob(){} 34 | 35 | bool on_motion_notify(GdkEventMotion* event) { 36 | float offset = (origin_y - event->y) * range / sensitivity; 37 | float new_value = origin_val + ((step == 0.0) ? offset : step * floor ((offset / step) + 0.5)); 38 | if (new_value > max) { 39 | new_value = max; 40 | } else if (new_value < min) { 41 | new_value = min; 42 | } 43 | value = new_value; 44 | value_changed.emit(); 45 | refresh(); 46 | return true; 47 | } 48 | 49 | bool on_expose_event(GdkEventExpose* event) { 50 | static Gdk::Color bgColor = Gdk::Color("black"); 51 | static Gdk::Color activeColor = Gdk::Color("black"); 52 | static Gdk::Color passiveColor = Gdk::Color("white"); 53 | Glib::RefPtr window = get_window(); 54 | 55 | if (window) { 56 | Cairo::RefPtr cr = window->create_cairo_context(); 57 | 58 | Gtk::Allocation allocation = get_allocation(); 59 | const int width = allocation.get_width(); 60 | const int height = allocation.get_height(); 61 | 62 | int xc = width / 2; 63 | int yc = height / 2; 64 | double val = (value - min) / (max - min); 65 | 66 | double angle = (0.75 + val * 1.5) * M_PI; 67 | //double angle_start = 0.75 * M_PI; 68 | //double angle_end = 2.25 * M_PI; 69 | 70 | cr->set_antialias(ANTIALIAS_SUBPIXEL); 71 | 72 | // radial gradient 73 | cr->save(); 74 | Cairo::RefPtr radial = Cairo::RadialGradient::create(xc, yc, radius, xc - 2.0, yc - 2.0, radius); 75 | radial->add_color_stop_rgba(0, 0.0, 0.0, 0.0, 0.5); 76 | radial->add_color_stop_rgba(1, 0.0, 0.0, 0.0, 0.0); 77 | cr->set_source(radial); 78 | cr->arc(xc, yc, radius * 1.2, 0.0, 2 * M_PI); 79 | cr->fill(); 80 | cr->restore(); 81 | 82 | // arc 83 | cr->save(); 84 | Gdk::Cairo::set_source_color(cr, bgColor); 85 | cr->arc(xc, yc, radius, 0, 2.0 * M_PI); 86 | cr->set_line_width(line_width); 87 | cr->stroke(); 88 | cr->restore(); 89 | 90 | // line 91 | cr->save(); 92 | cr->move_to(xc + 0.3 * radius * cos(angle), yc + 0.3 * radius * sin(angle)); 93 | cr->line_to(xc + 0.9 * radius * cos(angle), yc + 0.9 * radius * sin(angle)); 94 | cr->set_line_width(line_width); 95 | cr->stroke(); 96 | cr->restore(); 97 | } 98 | 99 | return true; 100 | } 101 | 102 | bool on_button_press(GdkEventButton* event) { 103 | origin_val = value; 104 | origin_y = event->y; 105 | return true; 106 | } 107 | 108 | float get_value() { 109 | return value; 110 | } 111 | 112 | void set_value(float val) { 113 | value = val; 114 | } 115 | 116 | void set_radius(float r) { 117 | radius = r; 118 | } 119 | 120 | void set_line_width(float w) { 121 | line_width = w; 122 | } 123 | 124 | void set_size(int s) { 125 | set_size_request(s, s); 126 | } 127 | 128 | void refresh() { 129 | Glib::RefPtr win = get_window(); 130 | if (win) { 131 | Gdk::Rectangle r(0, 0, get_allocation().get_width(), get_allocation().get_height()); 132 | win->invalidate_rect(r, false); 133 | } 134 | } 135 | 136 | sigc::signal signal_value_changed() { 137 | return value_changed; 138 | } 139 | 140 | Gtk::Widget* get_widget() { 141 | return this; 142 | } 143 | 144 | void connect(sigc::slot slot) { 145 | value_changed.connect( slot ); 146 | } 147 | 148 | protected: 149 | 150 | float value; 151 | 152 | float min, max, step; 153 | 154 | float line_width; 155 | 156 | float radius; 157 | 158 | float range, sensitivity, origin_val, origin_y; 159 | 160 | sigc::signal value_changed; 161 | 162 | }; 163 | 164 | #endif //KNOB_H 165 | -------------------------------------------------------------------------------- /src/long-note-test.cpp: -------------------------------------------------------------------------------- 1 | #include "analogue.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main() { 11 | int bufferSize = 88200; 12 | float buffer_l[bufferSize]; 13 | float buffer_r[bufferSize]; 14 | 15 | float controls[p_n_ports-3]; 16 | for (int i = 0; i < p_n_ports-3; i++) { 17 | controls[i] = p_port_meta[i].default_value; 18 | } 19 | 20 | // init Analogue 21 | Analogue analogue(44100.0f); 22 | // connect audio ports 23 | analogue.connect_port(p_audio_l, &buffer_l[0]); 24 | analogue.connect_port(p_audio_r, &buffer_r[0]); 25 | // connect control ports 26 | for (int i = 3; i < p_n_ports; i++) { 27 | //std::cout << "connect " << i << std::endl; 28 | analogue.connect_port(i, &controls[i-3]); 29 | } 30 | 31 | // override defaults 32 | //controls[p_jetFilterFreq - 3] = 4000.0f; 33 | //controls[p_boreFilterFreq - 3] = 4000.0f; 34 | //controls[p_noiseFreqCutoff - 3] = 1500.0; 35 | //controls[p_jetReflection - 3] = 0.6; 36 | //controls[p_endReflection - 3] = 0.4; 37 | 38 | //int format=SF_FORMAT_WAV | SF_FORMAT_PCM_16; 39 | int format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; 40 | int channels = 1; 41 | int sampleRate = 44100; 42 | 43 | const char* names[] = {"c","c#","d","d#","e","f","f#","g","g#","a","a#","b"}; 44 | 45 | for (int i = 0; i < 12; i++) { 46 | // render output 47 | analogue.on(64 + i, 64); 48 | analogue.render(0, 44100); 49 | analogue.off(64 + i, 0); 50 | analogue.render(44100, bufferSize); 51 | 52 | // write to WAV 53 | char filename[10]; 54 | sprintf(filename, "gen/%s4.wav", names[i]); 55 | 56 | SndfileHandle outfile(filename, SFM_WRITE, format, channels, sampleRate); 57 | if (!outfile) { 58 | return -1; 59 | } 60 | outfile.write(&buffer_l[0], bufferSize); 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /src/panel.h: -------------------------------------------------------------------------------- 1 | #ifndef PANEL_H 2 | #define PANEL_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace Gtk; 8 | 9 | class Panel : public Frame { 10 | public: 11 | Panel(const char* title, Widget* toggle, Widget* content) { 12 | set_border_width(5); 13 | set_shadow_type(SHADOW_OUT); 14 | strcpy(bold_title, ""); 15 | strcat(bold_title, title); 16 | strcat(bold_title, ""); 17 | 18 | Label* label = manage(new Label(bold_title)); 19 | label->set_use_markup(); 20 | 21 | VBox* main = manage(new VBox()); 22 | HBox* header = manage(new HBox()); 23 | header->pack_start(*label, false, false); 24 | header->pack_end(*toggle, false, false); 25 | main->set_border_width(2); 26 | main->pack_start(*header); 27 | main->pack_start(*content); 28 | add(*main); 29 | } 30 | 31 | private: 32 | char bold_title[40]; 33 | }; 34 | 35 | #endif //PANEL_H 36 | -------------------------------------------------------------------------------- /src/printttl.cpp: -------------------------------------------------------------------------------- 1 | #include "dsp.h" 2 | #include "dump-rdf.h" 3 | 4 | int main() { 5 | DumpRDFUI* ui = new DumpRDFUI(); 6 | 7 | dsp* synth = createDSP(); 8 | synth->init(44100); 9 | synth->buildUserInterface(ui); 10 | 11 | delete ui; 12 | delete synth; 13 | }; 14 | -------------------------------------------------------------------------------- /src/toggle.h: -------------------------------------------------------------------------------- 1 | #ifndef TOGGLE_H 2 | #define TOGGLE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "changeable.h" 9 | 10 | class Toggle : public Gtk::DrawingArea, public Changeable { 11 | public: 12 | 13 | Toggle(bool invert = false) : invert(invert) { 14 | set_size_request(15, 15); 15 | value = 1.0f; 16 | 17 | add_events( Gdk::EXPOSURE_MASK | Gdk::BUTTON_PRESS_MASK); 18 | signal_button_press_event().connect(mem_fun(this, &Toggle::on_button_press)); 19 | } 20 | 21 | bool on_expose_event(GdkEventExpose* event) { 22 | static Gdk::Color bgColor = Gdk::Color("black"); 23 | Glib::RefPtr window = get_window(); 24 | 25 | if (window) { 26 | Cairo::RefPtr cr = window->create_cairo_context(); 27 | 28 | Gtk::Allocation allocation = get_allocation(); 29 | int xc = allocation.get_width() / 2; 30 | int yc = allocation.get_height() / 2; 31 | 32 | cr->set_antialias(ANTIALIAS_SUBPIXEL); 33 | 34 | Gdk::Cairo::set_source_color(cr, bgColor); 35 | cr->arc(xc, yc, 5.0, 0, 2.0 * M_PI); 36 | if ((value == 1.0f && !invert) || (value == 0.0f && invert)) { 37 | cr->fill(); 38 | } else { 39 | cr->stroke(); 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | 46 | bool on_button_press(GdkEventButton* event) { 47 | if(event->type == GDK_BUTTON_PRESS && event->button == 1) { 48 | value = (value == 1.0) ? 0.0 : 1.0f; 49 | refresh(); 50 | value_changed.emit(); 51 | return true; 52 | } else { 53 | return false; 54 | } 55 | } 56 | 57 | float get_value() { 58 | return value; 59 | } 60 | 61 | void set_value(float val) { 62 | value = val; 63 | } 64 | 65 | Gtk::Widget* get_widget() { 66 | return this; 67 | } 68 | 69 | void connect(sigc::slot s) { 70 | value_changed.connect( s ); 71 | } 72 | 73 | void refresh() { 74 | Glib::RefPtr win = get_window(); 75 | if (win) { 76 | Gdk::Rectangle r(0, 0, get_allocation().get_width(), get_allocation().get_height()); 77 | win->invalidate_rect(r, false); 78 | } 79 | } 80 | 81 | private: 82 | 83 | bool invert; 84 | 85 | float value; 86 | 87 | sigc::signal value_changed; 88 | }; 89 | 90 | #endif //TOGGLE_H 91 | -------------------------------------------------------------------------------- /test/dpw.dsp: -------------------------------------------------------------------------------- 1 | import("math.lib"); 2 | 3 | dpw_oscillator(type, freq, width) = phase(freq) <: select2(type > 0, sin(2*PI*_), dpw) 4 | with { 5 | 6 | dpw = bi : shape <: -(mem) : scale : (SR/freq'*_); 7 | 8 | // type tri saw square 9 | shape(x) = select3(type-1, x-x*abs(x), x*x, 0); 10 | scale = select3(type-1, 0.5, 0.25, 1)*_; 11 | 12 | }; 13 | 14 | phase(freq) = (+(q) : mod1) ~ _ 15 | with { 16 | q = float(freq)/float(SR); 17 | }; 18 | 19 | // unipolar to bipolar 20 | bi = 2.0*_ - 1.0; 21 | 22 | mod1 = fmod(_, 1.0); 23 | -------------------------------------------------------------------------------- /test/oscillators.py: -------------------------------------------------------------------------------- 1 | from scipy.signal import * 2 | import matplotlib 3 | import pylab 4 | 5 | f0 = 441. # fundamental frequency 6 | fs = 44100. # sample rate 7 | si = f0/fs # phase increment 8 | P = int(fs/f0) # period 9 | t = arange(0,4+si,si) # time vector 10 | 11 | # plot 12 | 13 | fig = pylab.figure() 14 | fig.canvas.set_window_title('Elementary Phaseshapers') 15 | ticks = matplotlib.ticker.FixedLocator([0,0.5,1]) 16 | 17 | def preplot(id): 18 | id += 610 19 | p = pylab.subplot(id) 20 | p.grid(True) 21 | p.yaxis.set_major_locator(ticks) 22 | return p 23 | 24 | def postplot(p, showticklabels=False): 25 | if not showticklabels: 26 | p.xaxis.set_ticklabels('') 27 | else: 28 | pylab.xlabel('Time (samples, f0=441 Hz, fs=44.1 kHz)') 29 | pylab.ylim(-1.1, 1.1) 30 | pylab.xlim(0,301) 31 | pylab.ylabel('Level') 32 | 33 | def saw_wave(x): 34 | pow2 = x * x 35 | rv = zeros(len(x)) 36 | for n in range(0,len(x)): 37 | rv[n] = pow2[n] - pow2[n-1] 38 | rv = rv * fs/(4*f0) 39 | return rv 40 | 41 | def tri_wave(x): 42 | par = x - (x*abs(x)) 43 | rv = zeros(len(x)) 44 | for n in range(0,len(x)): 45 | rv[n] = par[n] - par[n-1] 46 | rv = rv * fs/(2*f0) 47 | return rv 48 | 49 | phi = t % 1 50 | steps = 2 * phi - 1 51 | saw = saw_wave(steps) 52 | tri = tri_wave(steps) 53 | 54 | # -- unipolar modulo counter 55 | #p1 = preplot(1) 56 | #p1.plot(phi, "k", lw=2) 57 | #postplot(p1) 58 | 59 | # -- steps 60 | p1 = preplot(1) 61 | p1.plot(steps, "k", lw=2) 62 | postplot(p1) 63 | 64 | # -- saw 65 | p2 = preplot(2) 66 | p2.plot(saw, "k", lw=2) 67 | postplot(p2) 68 | 69 | # -- triangle 70 | p3 = preplot(3) 71 | p3.plot(tri, "k", lw=2) 72 | postplot(p3) 73 | 74 | # TODO square 75 | 76 | pylab.show() 77 | 78 | -------------------------------------------------------------------------------- /test/saw-test.dsp: -------------------------------------------------------------------------------- 1 | osclib = library("oscillator.lib"); 2 | 3 | process = osclib.saw1(440); 4 | -------------------------------------------------------------------------------- /test/saw2-test.dsp: -------------------------------------------------------------------------------- 1 | import("dpw.dsp"); 2 | 3 | process = dpw_oscillator(2.0, 440.0, 0.5); 4 | -------------------------------------------------------------------------------- /test/sin-test.dsp: -------------------------------------------------------------------------------- 1 | osclib = library("oscillator.lib"); 2 | 3 | process = osclib.osc(440); 4 | -------------------------------------------------------------------------------- /test/sin2-test.dsp: -------------------------------------------------------------------------------- 1 | import("dpw.dsp"); 2 | 3 | process = dpw_oscillator(0.0, 440.0, 0.5); 4 | -------------------------------------------------------------------------------- /test/square-test.dsp: -------------------------------------------------------------------------------- 1 | osclib = library("oscillator.lib"); 2 | 3 | process = squarewave(440, 0.5); 4 | 5 | squarewave(freq, width) = 2.0 * osclib.pulsetrainpos(freq, width) - 1.0; 6 | -------------------------------------------------------------------------------- /test/square2-test.dsp: -------------------------------------------------------------------------------- 1 | import("dpw.dsp"); 2 | 3 | process = dpw_oscillator(3.0, 440.0, 0.5); 4 | -------------------------------------------------------------------------------- /test/tests.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "saw.cpp" 5 | #include "saw2.cpp" 6 | #include "sin.cpp" 7 | #include "sin2.cpp" 8 | #include "square.cpp" 9 | #include "square2.cpp" 10 | #include "tri.cpp" 11 | #include "tri2.cpp" 12 | 13 | #define SR 44100 14 | #define SIZE 22050 15 | 16 | void process(dsp* processor, const char* filename) { 17 | static int format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; 18 | static int channels = 1; 19 | static int sampleRate = SR; 20 | 21 | float buffer[SIZE]; 22 | float *outputs[] = {buffer}; 23 | 24 | processor->init(SR); 25 | processor->compute(SIZE, 0, outputs); 26 | 27 | SndfileHandle outfile(filename, SFM_WRITE, format, channels, sampleRate); 28 | outfile.write(&buffer[0], SIZE); 29 | delete processor; 30 | } 31 | 32 | int main() { 33 | process(new sawdsp(), "gen/saw.wav"); 34 | process(new saw2dsp(), "gen/saw2.wav"); 35 | process(new sindsp(), "gen/sin.wav"); 36 | process(new sin2dsp(), "gen/sin2.wav"); 37 | process(new squaredsp(), "gen/square.wav"); 38 | process(new square2dsp(), "gen/square2.wav"); 39 | process(new tridsp(), "gen/tri.wav"); 40 | process(new tri2dsp(), "gen/tri2.wav"); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /test/tri-test.dsp: -------------------------------------------------------------------------------- 1 | import("math.lib"); 2 | osclib = library("oscillator.lib"); 3 | 4 | process = triangle(440); 5 | 6 | triangle(freq) = osclib.saw1(freq) : abs : (_*2.0-1.0); 7 | -------------------------------------------------------------------------------- /test/tri2-test.dsp: -------------------------------------------------------------------------------- 1 | import("dpw.dsp"); 2 | 3 | process = dpw_oscillator(1.0, 440.0, 0.5); 4 | --------------------------------------------------------------------------------