diff options
author | Damien Zammit <damien@zamaudio.com> | 2017-11-29 20:45:58 +1100 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2017-11-29 20:45:58 +1100 |
commit | 89635316558a1128bc1a0b399ad5cd7817e74553 (patch) | |
tree | 2de3ba3b6e0b95b9be172f00557297f2a30762b4 | |
parent | e8868b75437ee83d7f012581cc72de0ae4261c2e (diff) |
ZamSFZ: Resample sfz samples when host samplerate mismatches sfz
-rw-r--r-- | plugins/ZamSFZ/Sfz.cpp | 62 | ||||
-rw-r--r-- | plugins/ZamSFZ/Sfz.hpp | 6 | ||||
-rw-r--r-- | plugins/ZamSFZ/ZamSFZPlugin.cpp | 5 |
3 files changed, 64 insertions, 9 deletions
diff --git a/plugins/ZamSFZ/Sfz.cpp b/plugins/ZamSFZ/Sfz.cpp index eddc5fd..5630ae5 100644 --- a/plugins/ZamSFZ/Sfz.cpp +++ b/plugins/ZamSFZ/Sfz.cpp @@ -2,7 +2,6 @@ #include <iostream> #include <fstream> #include <string> -#define BLOCK_SIZE 512 void Sfz::remapvelocityranges(::sfz::Instrument *inst) { @@ -95,8 +94,55 @@ void Sfz::remapvelocityranges(::sfz::Instrument *inst) } } -void Sfz::readsamples(SNDFILE *infile, - int channels, int note, int layer) +void Sfz::readsamples_resample(SNDFILE *infile, SF_INFO *sfinfo, int note, int layer, int target_rate) +{ + float buf[sfinfo->channels * BLOCK_SIZE]; + float tmpbuf_pre[2][MAX_SAMPLES] = {0.f}; + float tmpbuf_post[2][MAX_SAMPLES] = {0.f}; + SRC_DATA src; + int k, m, readcount, i; + int maxch = std::min(sfinfo->channels, 2); + + // Read samples in blocks to a flat buffer + i = 0; + while (i < MAX_SAMPLES && (readcount = sf_readf_float (infile, buf, BLOCK_SIZE)) > 0) { + for (k = 0 ; k < readcount ; k++) { + for (m = 0; m < maxch; m++) { + tmpbuf_pre[m][i+k] = buf[k*sfinfo->channels + m]; + } + } + i += readcount; + } + + // Resample... + src.data_in = &tmpbuf_pre[0][0]; + src.data_out = &tmpbuf_post[0][0]; + src.input_frames = MAX_SAMPLES; + src.output_frames = MAX_SAMPLES; + src.src_ratio = (double)target_rate / (double)sfinfo->samplerate; + if (!src_simple(&src, CONVERTER_TYPE, 1)) { + // Write left samples out to sample buffer + for (i = 0; i < src.output_frames_gen; i++) { + sample[note][layer][0][i] = tmpbuf_post[0][i]; + } + } + + if (maxch == 2) { + src.data_in = &tmpbuf_pre[1][0]; + src.data_out = &tmpbuf_post[1][0]; + src.input_frames = MAX_SAMPLES; + src.output_frames = MAX_SAMPLES; + src.src_ratio = (double)target_rate / (double)sfinfo->samplerate; + if (!src_simple(&src, CONVERTER_TYPE, 1)) { + // Write right samples out to sample buffer + for (i = 0; i < src.output_frames_gen; i++) { + sample[note][layer][1][i] = tmpbuf_post[1][i]; + } + } + } +} + +void Sfz::readsamples(SNDFILE *infile, int channels, int note, int layer) { float buf[channels*BLOCK_SIZE]; int k, m, readcount, i; @@ -104,7 +150,7 @@ void Sfz::readsamples(SNDFILE *infile, i = 0; while (i < MAX_SAMPLES && (readcount = sf_readf_float (infile, buf, BLOCK_SIZE)) > 0) { for (k = 0 ; k < readcount ; k++) { - for (m = 0 ; m < channels ; m++) { + for (m = 0; m < std::min(channels, 2); m++) { sample[note][layer][m][i+k] = buf[k*channels + m]; } } @@ -138,7 +184,7 @@ void Sfz::clearsamples() } } -void Sfz::loadsamples(std::string path, std::string filename) +void Sfz::loadsamples(std::string path, std::string filename, int target_rate) { int note, i, j, k, key; ::sfz::SFZParser sfzfile; @@ -175,8 +221,12 @@ void Sfz::loadsamples(std::string path, std::string filename) puts (sf_strerror (NULL)); printf("File: %s\n",fullsamplepath.c_str()); } - readsamples (infile, sfinfo.channels, note, layers[note].max); k = layers[note].max; + if ((int)sfinfo.samplerate == target_rate) { + readsamples (infile, sfinfo.channels, note, k); + } else { + readsamples_resample (infile, &sfinfo, note, k, target_rate); + } layers[note].l[k].lovel = sfzinstrument->regions[i]->lovel; layers[note].l[k].hivel = sfzinstrument->regions[i]->hivel; layers[note].l[k].lokey = sfzinstrument->regions[i]->lokey; diff --git a/plugins/ZamSFZ/Sfz.hpp b/plugins/ZamSFZ/Sfz.hpp index 5566495..3240310 100644 --- a/plugins/ZamSFZ/Sfz.hpp +++ b/plugins/ZamSFZ/Sfz.hpp @@ -5,9 +5,12 @@ #include "libsfz/sfz.h" #include <rubberband/RubberBandStretcher.h> #include <sndfile.h> +#include <samplerate.h> #include <math.h> #define MAX_LAYERS 12 #define MAX_SAMPLES 130000 +#define BLOCK_SIZE 512 +#define CONVERTER_TYPE SRC_SINC_BEST_QUALITY class Sfz { @@ -30,8 +33,9 @@ public: layer_t layers[128]; void clearsamples(); - void loadsamples(std::string path, std::string filename); + void loadsamples(std::string path, std::string filename, int target_rate); void readsamples (SNDFILE *infile, int channels, int note, int layer); + void readsamples_resample (SNDFILE *infile, SF_INFO *sfinfo, int note, int layer, int target_rate); void pitchshiftsamples(int srate); void remapvelocityranges(::sfz::Instrument *inst); }; diff --git a/plugins/ZamSFZ/ZamSFZPlugin.cpp b/plugins/ZamSFZ/ZamSFZPlugin.cpp index 1cd026c..16d12d5 100644 --- a/plugins/ZamSFZ/ZamSFZPlugin.cpp +++ b/plugins/ZamSFZ/ZamSFZPlugin.cpp @@ -98,6 +98,7 @@ void ZamSFZPlugin::setParameterValue(uint32_t index, float value) void ZamSFZPlugin::setState(const char* key, const char* value) { if (strcmp(key, "filepath") == 0) { + int curr_srate = (int)getSampleRate(); char *tmp; char file[1024] = {0}; snprintf(file, 1024, "%s", value); @@ -107,8 +108,8 @@ void ZamSFZPlugin::setState(const char* key, const char* value) loading = true; printf("Path: %s\nFile: %s\n", path.c_str(), filename.c_str()); sfz.clearsamples(); - sfz.loadsamples(path, filename); - sfz.pitchshiftsamples((int)getSampleRate()); + sfz.loadsamples(path, filename, curr_srate); + sfz.pitchshiftsamples(curr_srate); loading = false; } } |