From 7c875a14b73d844f4f3b8390e4463610262d9415 Mon Sep 17 00:00:00 2001 From: Florian Jung Date: Wed, 11 Apr 2012 16:36:45 +0200 Subject: added FM-list (brings between 0% and 15% performance improvement) cast-optimisation programs gets a better operator= commented out segfaulting cleanup() --- TODO | 5 ++++- synth/Makefile | 2 +- synth/OPTIMIZATIONS | 14 ++++++++++++++ synth/avg_stddev.py | 27 +++++++++++++++++++++++++++ synth/main.cpp | 2 +- synth/note.cpp | 41 ++++++++++++++++++++++++++++++++--------- synth/note.h | 3 +++ synth/profile.sh | 12 ++++++++++++ synth/programs.cpp | 20 ++++++++++++++++---- 9 files changed, 110 insertions(+), 16 deletions(-) create mode 100755 synth/avg_stddev.py create mode 100755 synth/profile.sh diff --git a/TODO b/TODO index 29f49cc..dffbaf4 100644 --- a/TODO +++ b/TODO @@ -6,8 +6,11 @@ !!! SEGFAULT wegen nicht synchronisierter kommunikation bei panic()! +!!! cleanup() verursacht SEGFAULT, jedenfalls wenn man es durch + callgrind laufen lässt + TODO für den synth - o notes kriegen verkettete liste für FM-affect: "kein einfluss" + x notes kriegen verkettete liste für FM-affect: "kein einfluss" steht dann garnicht in der liste (macht aus O(n²) ein O(n)) (macht notencompiler hoffentlich obsolet) o evtl wieder AM implementieren: hätte hoffentlich dann keinen diff --git a/synth/Makefile b/synth/Makefile index 01e27ee..d97ec90 100644 --- a/synth/Makefile +++ b/synth/Makefile @@ -1,6 +1,6 @@ CXX=g++ #CFLAGS=-Wall -O2 -CFLAGS=-Wall -O -g +CFLAGS=-Wall -O3 -g CXXFLAGS=$(CFLAGS) LDFLAGS=-lm `pkg-config --cflags --libs jack` diff --git a/synth/OPTIMIZATIONS b/synth/OPTIMIZATIONS index 14d5f4f..4a22fd4 100644 --- a/synth/OPTIMIZATIONS +++ b/synth/OPTIMIZATIONS @@ -2,6 +2,20 @@ Sinnlose Optimierungen o if(foo.fm_strength!=0) ...: kein effekt, höchstens leichter anstieg! Mögliche Optimierungen + o ??? if (out>0) und was mit lfo: vlt das if weglassen? + o 1% noten kriegen direkten pointer auf ihre waves; (custom_wave-check entfällt) + x 15% fm-liste (die nur die oscs mit fm[i]!=0 enthält) statt + in O(n²) alle durchzutesten: bei 2 oszillatoren kein effekt, + bei 9 oscs der form 1->2->3...->9 (also 9 mod-beziehungen) + 17% verbesserung + o ??? Channel::get_sample() soll mehrere frames berechnen. + soll außerdem das /ONE*VOL_FACTOR gleich mit einrechnen + (kann einmalig gleich mit Channel::volume verrechnet werden) + o 10% BOTTLENECKs in note.cpp fixen. actual_freq und abhängigkeiten + nur dann berechnen, wenn sie sich auch ändert (set_freq, porta, + pitchbend, freq-envelope) + o ??? log_verbose sollte ggf. garnicht interpretiert werden? + o 10% filter ganz auf fixed_t umstellen? o 5% envelope::get_level nur alle n frames arbeiten lassen, sonst cachen? o 2% bei LFOs: bei jedem LFO-update die werte für env-max, freqfactor diff --git a/synth/avg_stddev.py b/synth/avg_stddev.py new file mode 100755 index 0000000..421a1aa --- /dev/null +++ b/synth/avg_stddev.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys +import math + +vals=[] +sum=0 +cnt=0 + +for line in sys.stdin: + num=float(line) + vals.append(num) + sum=sum+num + cnt=cnt+1 + +avg=sum/cnt + +stddev=0 +for val in vals: + stddev=stddev+ (val-avg)**2 + +stddev=stddev/cnt +stddev=math.sqrt(stddev) + + +print "avg is " , avg +print "stddev is " , stddev diff --git a/synth/main.cpp b/synth/main.cpp index 95a6a7b..5427b75 100644 --- a/synth/main.cpp +++ b/synth/main.cpp @@ -199,7 +199,7 @@ int main(int argc, char** argv) do_in_synth_cli(); - cleanup(); + //cleanup(); } catch(string err) { diff --git a/synth/note.cpp b/synth/note.cpp index 54267a8..f468a79 100644 --- a/synth/note.cpp +++ b/synth/note.cpp @@ -50,6 +50,11 @@ Note::Note(int n, float v, program_t &prg, jack_nframes_t pf, fixed_t pb, int pr copy(&prg.osc_settings[0],&prg.osc_settings[n_oscillators],oscillator); copy(&prg.osc_settings[0],&prg.osc_settings[n_oscillators],orig.oscillator); + fm_oscs=new list[n_oscillators]; + for (int i=0;i>SCALE; oscillator[i].freq_env_amount=orig.oscillator[i].freq_env_amount*pfactor.freq_env_amount[i] /ONE; //because it's a float + fm_oscs[i].clear(); for (int j=0;j>SCALE; + if (oscillator[i].fm_strength[j]!=0) + fm_oscs[i].push_back(j); + } } filter_params.env_amount=orig.filter_params.env_amount*pfactor.filter_env /ONE; filter_params.freqfactor_offset=orig.filter_params.freqfactor_offset*pfactor.filter_offset /ONE; @@ -321,7 +331,7 @@ fixed_t Note::get_sample() if (freq!=dest_freq) { // the div.by.zero if p_frames=0 is avoided because then the - // if-condition below is always true + // if-condition below would always be true if (portamento_t>=portamento_frames) freq=dest_freq; else //will only happen if p_t < p_frames -> p_frames is always > 0 -> div. ok @@ -342,11 +352,16 @@ fixed_t Note::get_sample() fixed_t fm=0; fixed_t out=0; - int i,j; + int i; if (sync_factor) { - sync_phase+=(actual_freq*sync_factor/samp_rate) >> SCALE; + sync_phase+=(actual_freq*sync_factor/samp_rate) >> SCALE; // BOTTLENECK + // phase-increment depends on: + // - actual_freq (which depends on freq and pitchbend) + // steadily updated while portamento-ing and whenever a pitchbend comes in + // - sync_factor: only updated manually + // - samp_rate: never changes if (sync_phase >= ONE) { @@ -382,9 +397,9 @@ fixed_t Note::get_sample() { fm=0; - for (j=0;j::iterator j=fm_oscs[i].begin(), end=fm_oscs[i].end(); j!=end; j++) + fm+=old_oscval[*j]*oscillator[i].fm_strength[*j]; fm=fm>>SCALE; @@ -392,18 +407,26 @@ fixed_t Note::get_sample() if (oscillator[i].vibrato_depth!=0) oscillator[i].phase+=( (curr_lfo[oscillator[i].vibrato_lfo][oscillator[i].vibrato_depth]*actual_freq >>SCALE)*oscillator[i].factor/samp_rate)>>SCALE; else - oscillator[i].phase+=(actual_freq*oscillator[i].factor/samp_rate)>>SCALE; + oscillator[i].phase+=(actual_freq*oscillator[i].factor/samp_rate)>>SCALE; // BOTTLENECK + // phase-increment depends on: + // - actual_freq (which depends on freq and pitchbend) + // steadily updated while portamento-ing and whenever a pitchbend comes in + // - the vibrato-lfo: needs update whenever this lfo is updated + // - factor (which depends on the freq envelope) + // steadily updated every env_frames frames + // - samp_rate: never changes if (oscillator[i].custom_wave) { //sampler custom_wave_t *cw=oscillator[i].custom_wave; - oscval[i]=cw->wave[ ((oscillator[i].phase + fm) * cw->samp_rate >>(2*SCALE)) % cw->wave_len ] * envval[i] >> (SCALE); + oscval[i]=cw->wave[ ((unsigned int)((oscillator[i].phase + fm) * cw->samp_rate >>(2*SCALE))) % cw->wave_len ] * envval[i] >> (SCALE); } else { //normal oscillator - oscval[i]=wave[oscillator[i].waveform][ ((oscillator[i].phase + fm) * WAVE_RES >>SCALE) % WAVE_RES ] * envval[i] >> (SCALE); + //optimisation: the unsigned int cast avoids a slow 64bit modulo calculation. ca. 8% speed gain. same above. + oscval[i]=wave[oscillator[i].waveform][ ((unsigned int)((oscillator[i].phase + fm) * WAVE_RES >>SCALE)) % WAVE_RES ] * envval[i] >> (SCALE); } if (oscillator[i].tremolo_depth!=0) diff --git a/synth/note.h b/synth/note.h index 7181f6d..379f2b1 100644 --- a/synth/note.h +++ b/synth/note.h @@ -3,6 +3,8 @@ #include +#include + #include "programs.h" #include "envelope.h" #include "fixed.h" @@ -43,6 +45,7 @@ class Note : public NoteSkel fixed_t *old_oscval; int n_oscillators; oscillator_t *oscillator; + std::list* fm_oscs; fixed_t sync_factor; fixed_t sync_phase; diff --git a/synth/profile.sh b/synth/profile.sh new file mode 100755 index 0000000..921a5d4 --- /dev/null +++ b/synth/profile.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +if [ x$1 = x ]; then + cnt=5 +else + cnt=$1 +fi + +for ((i=1;i<=$cnt;i++)); do + /usr/bin/time -p ./synth -p 0:analog.prog -i 60 -x 1000:1 -a -m 2>&1 | grep 'user ' | sed 's/user //'; + #echo "$i / $cnt done" 1>&2 +done | python avg_stddev.py diff --git a/synth/programs.cpp b/synth/programs.cpp index 5dae4ed..63078c0 100644 --- a/synth/programs.cpp +++ b/synth/programs.cpp @@ -26,15 +26,27 @@ oscillator_t& oscillator_t::operator=(const oscillator_t &that) { if (this!=&that) { + this->output=that.output; + this->waveform=that.waveform; + this->factor=that.factor; + this->freq_env_amount=that.freq_env_amount; + this->freq_env=that.freq_env; + this->phase=that.phase; + this->tremolo_depth=that.tremolo_depth; + this->tremolo_lfo=that.tremolo_lfo; + this->vibrato_depth=that.vibrato_depth; + this->vibrato_lfo=that.vibrato_lfo; + this->custom_wave=that.custom_wave; + this->n_osc=that.n_osc; + this->ksl=that.ksl; + this->ksr=that.ksr; + this->sync=that.sync; + if (this->fm_strength) delete [] this->fm_strength; - memcpy(this, &that, sizeof(*this)); - this->fm_strength=new fixed_t[n_osc]; memcpy(this->fm_strength, that.fm_strength, sizeof(*that.fm_strength)*n_osc); - - this->custom_wave=that.custom_wave; return *this; } -- cgit v1.2.1