summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2015-02-16 21:06:35 +1100
committerDamien Zammit <damien@zamaudio.com>2015-02-16 21:06:35 +1100
commita0ca3ce20d3ca7d3ffcc214c784c9aedd7ecabc6 (patch)
treed222cfcc96a1ce02e646c0b6138d746c2a2774c7
parent0ed0edb04633402615b101a01bbe163dbdeb6ba0 (diff)
Use librubberband to pitch shift samples for ZamSFZ
Signed-off-by: Damien Zammit <damien@zamaudio.com>
-rw-r--r--Makefile.mk2
-rw-r--r--plugins/ZamSFZ/Sfz.cpp45
-rw-r--r--plugins/ZamSFZ/Sfz.hpp4
-rw-r--r--plugins/ZamSFZ/ZamSFZPlugin.cpp1
-rw-r--r--plugins/ZamSFZ/ZamSFZUI.cpp4
5 files changed, 47 insertions, 9 deletions
diff --git a/Makefile.mk b/Makefile.mk
index 9aa5c72..64c15b7 100644
--- a/Makefile.mk
+++ b/Makefile.mk
@@ -26,7 +26,7 @@ BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections
ifneq ($(NOOPT),true)
BASE_OPTS += -mtune=generic -msse -msse2 -mfpmath=sse
endif
-LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-O1 -Wl,--as-needed -Wl,--gc-sections -Wl,--strip-all $(shell pkg-config --libs sndfile)
+LINK_OPTS = -fdata-sections -ffunction-sections -Wl,-O1 -Wl,--as-needed -Wl,--gc-sections -Wl,--strip-all $(shell pkg-config --libs sndfile rubberband)
ifeq ($(MACOS),true)
# MacOS linker flags
diff --git a/plugins/ZamSFZ/Sfz.cpp b/plugins/ZamSFZ/Sfz.cpp
index 91ff7e2..eed3099 100644
--- a/plugins/ZamSFZ/Sfz.cpp
+++ b/plugins/ZamSFZ/Sfz.cpp
@@ -64,13 +64,14 @@ void Sfz::loadsamples(std::string path, std::string filename)
} else {
for (i = 0; i < maxregions; i++) {
for (note = 0; note < 128; note++) {
- key = 0;
if (sfzinstrument->regions[i]->lokey == sfzinstrument->regions[i]->hikey) {
key = sfzinstrument->regions[i]->lokey;
} else {
key = sfzinstrument->regions[i]->pitch_keycenter;
}
if (note == key) {
+ layers[note].keymiddle = key;
+ layers[note].dsemitones = 0;
infile = NULL;
if ((infile = sf_open(sfzinstrument->regions[i]->sample.c_str(), SFM_READ, &sfinfo)) == NULL) {
printf("Missing samples\n");
@@ -86,16 +87,48 @@ void Sfz::loadsamples(std::string path, std::string filename)
sf_close (infile);
printf("N-%d V-%d %s\n", note, k, sfzinstrument->regions[i]->sample.c_str());
layers[note].max++;
- break;
+ continue;
+ } else if (sfzinstrument->regions[i]->lokey <= note && sfzinstrument->regions[i]->hikey >= note) {
+ layers[note].keymiddle = key;
+ layers[note].dsemitones = note - key;
+ //printf("MainKey=%d NoteShiftTo=%d\n", key, note);
}
}
}
printf("All samples loaded, Woot!\n");
}
delete sfzfile;
- for (i = 0; i < 128; i++) {
- if (layers[i].max) {
- layers[i].max--;
+}
+
+void Sfz::pitchshiftsamples(int srate)
+{
+ ::RubberBand::RubberBandStretcher* rbl = NULL;
+ ::RubberBand::RubberBandStretcher* rbr = NULL;
+ int i,j;
+ for (i = 0; i < 128; i++) {
+ //printf("i=%d ds=%d\n", i, layers[i].dsemitones);
+ if (!(layers[i].dsemitones == 0)) {
+ int ii = layers[i].keymiddle;
+ //printf("Pitch shifting... %d\n", layers[i].dsemitones);
+ for (j = 0; j < layers[ii].max; j++) {
+ float const * const inl[] = {sample[ii][j][0]};
+ float const * const inr[] = {sample[ii][j][1]};
+ float * const outl[] = {sample[i][j][0]};
+ float * const outr[] = {sample[i][j][1]};
+ rbl = new ::RubberBand::RubberBandStretcher(srate, 1, 0, 1.0, pow(2.0, layers[i].dsemitones / 12.));
+ rbr = new ::RubberBand::RubberBandStretcher(srate, 1, 0, 1.0, pow(2.0, layers[i].dsemitones / 12.));
+
+ rbl->setMaxProcessSize(MAX_SAMPLES);
+ rbr->setMaxProcessSize(MAX_SAMPLES);
+ rbl->setExpectedInputDuration(MAX_SAMPLES);
+ rbr->setExpectedInputDuration(MAX_SAMPLES);
+ rbl->process(inl, MAX_SAMPLES, true);
+ rbr->process(inr, MAX_SAMPLES, true);
+ rbl->retrieve(outl, MAX_SAMPLES);
+ rbr->retrieve(outr, MAX_SAMPLES);
+ delete rbl;
+ delete rbr;
+ }
+ }
}
- }
}
diff --git a/plugins/ZamSFZ/Sfz.hpp b/plugins/ZamSFZ/Sfz.hpp
index ce7891e..5698283 100644
--- a/plugins/ZamSFZ/Sfz.hpp
+++ b/plugins/ZamSFZ/Sfz.hpp
@@ -3,6 +3,7 @@
#include <string.h>
#include <ctype.h>
#include "libsfz/sfz.h"
+#include <rubberband/RubberBandStretcher.h>
#include <sndfile.h>
#define MAX_LAYERS 8
#define MAX_SAMPLES 64000
@@ -21,6 +22,8 @@ public:
typedef struct {
int max;
+ int keymiddle;
+ int dsemitones;
hilo_t l[MAX_LAYERS];
} layer_t;
@@ -28,4 +31,5 @@ public:
void clearsamples();
void loadsamples(std::string path, std::string filename);
void readsamples (SNDFILE *infile, int channels, int note, int layer);
+ void pitchshiftsamples(int srate);
};
diff --git a/plugins/ZamSFZ/ZamSFZPlugin.cpp b/plugins/ZamSFZ/ZamSFZPlugin.cpp
index 9c436e5..93ca4a5 100644
--- a/plugins/ZamSFZ/ZamSFZPlugin.cpp
+++ b/plugins/ZamSFZ/ZamSFZPlugin.cpp
@@ -93,6 +93,7 @@ void ZamSFZPlugin::d_setState(const char* key, const char* value)
printf("Path: %s\nFile: %s\n", path.c_str(), filename.c_str());
sfz.clearsamples();
sfz.loadsamples(path, filename);
+ sfz.pitchshiftsamples((int)d_getSampleRate());
loading = false;
}
}
diff --git a/plugins/ZamSFZ/ZamSFZUI.cpp b/plugins/ZamSFZ/ZamSFZUI.cpp
index d5135cf..eccdf02 100644
--- a/plugins/ZamSFZ/ZamSFZUI.cpp
+++ b/plugins/ZamSFZ/ZamSFZUI.cpp
@@ -130,8 +130,8 @@ void ZamSFZUI::imageButtonClicked(ImageButton*, int)
gtk_widget_destroy(dialog);
*/
- d_setState("filepath", "/home/damien/Music/rhodes-nord/rhodes-nord.sfz");
- //d_setState("filepath", "/home/damien/Music/sfz/sfz LatelyBass/TX_LatelyBass.sfz");
+// d_setState("filepath", "/home/damien/Music/rhodes-nord/rhodes-nord.sfz");
+ d_setState("filepath", "/home/damien/Music/sfz/sfz LatelyBass/TX_LatelyBass.sfz");
}
void ZamSFZUI::onDisplay()