From a1ad26b49ce568a88dd462df8b216aa1311585c4 Mon Sep 17 00:00:00 2001 From: viniciusfersil123 Date: Sun, 5 Nov 2023 20:56:53 -0300 Subject: [PATCH 1/2] adds new granular player module and sampling folder --- CMakeLists.txt | 1 + Makefile | 6 ++ Source/Sampling/granularplayer.cpp | 79 +++++++++++++++++++++++++++ Source/Sampling/granularplayer.h | 88 ++++++++++++++++++++++++++++++ Source/daisysp.h | 3 + 5 files changed, 177 insertions(+) create mode 100644 Source/Sampling/granularplayer.cpp create mode 100644 Source/Sampling/granularplayer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 6481accf..b68b09af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,6 +47,7 @@ Source/PhysicalModeling/pluck.cpp Source/PhysicalModeling/resonator.cpp Source/PhysicalModeling/KarplusString.cpp Source/PhysicalModeling/stringvoice.cpp +Source/Sampling/granularplayer.cpp Source/Synthesis/blosc.cpp Source/Synthesis/fm2.cpp Source/Synthesis/formantosc.cpp diff --git a/Makefile b/Makefile index 805f0116..5ba50a2f 100644 --- a/Makefile +++ b/Makefile @@ -77,6 +77,10 @@ resonator \ stringvoice #PolyPluck +SAMPLING_MOD_DIR = Sampling +SAMPLING_MODULES = \ +granularplayer \ + SYNTHESIS_MOD_DIR = Synthesis SYNTHESIS_MODULES = \ blosc \ @@ -114,6 +118,7 @@ CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(EFFECTS_MOD_DIR)/$(EFFECTS_MODU CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(FILTER_MOD_DIR)/$(FILTER_MODULES)) CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(NOISE_MOD_DIR)/$(NOISE_MODULES)) CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(PHYSICAL_MODELING_MOD_DIR)/$(PHYSICAL_MODELING_MODULES)) +CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(SAMPLING_MOD_DIR)/$(SAMPLING_MODULES)) CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(SYNTHESIS_MOD_DIR)/$(SYNTHESIS_MODULES)) CPP_SOURCES += $(addsuffix .cpp, $(MODULE_DIR)/$(UTILITY_MOD_DIR)/$(UTILITY_MODULES)) @@ -196,6 +201,7 @@ C_INCLUDES = \ -I$(MODULE_DIR)/$(FILTER_MOD_DIR) \ -I$(MODULE_DIR)/$(NOISE_MOD_DIR) \ -I$(MODULE_DIR)/$(PHYSICAL_MODELING_MOD_DIR) \ +-I$(MODULE_DIR)/$(SAMPLING_MOD_DIR) \ -I$(MODULE_DIR)/$(SYNTHESIS_MOD_DIR) \ -I$(MODULE_DIR)/$(UTILITY_MOD_DIR) diff --git a/Source/Sampling/granularplayer.cpp b/Source/Sampling/granularplayer.cpp new file mode 100644 index 00000000..2456548a --- /dev/null +++ b/Source/Sampling/granularplayer.cpp @@ -0,0 +1,79 @@ +#include "granularplayer.h" + +using namespace daisysp; + +void GranularPlayer::Init(float* sample, int size, float sample_rate) +{ + /*initialize variables to private members*/ + sample_ = sample; + size_ = size; + sample_rate_ = sample_rate; + /*initialize phasors. phs2_ is initialized with a phase offset of 0.5f to create an overlapping effect*/ + phs_.Init(sample_rate_, 0, 0); + phsImp_.Init(sample_rate_, 0, 0); + phs2_.Init(sample_rate_, 0, 0.5f); + phsImp2_.Init(sample_rate_, 0, 0); + /*calculate sample frequency*/ + sample_frequency_ = sample_rate_ / size_; + /*initialize half cosine envelope*/ + for(int i = 0; i < 256; i++) + { + cosEnv_[i] = sinf((i / 256.0f) * M_PI); + } +} + +uint32_t GranularPlayer::WrapIdx(uint32_t idx, uint32_t sz) +{ + /*wraps idx to sz*/ + if(idx > sz) + { + idx = idx - sz; + return idx; + } + + return idx; +} + +float GranularPlayer::CentsToRatio(float cents) +{ + /*converts cents to ratio*/ + return powf(2.0f, cents / 1200.0f); +} + + +float GranularPlayer::MsToSamps(float ms, float samplerate) +{ + /*converts milliseconds to number of samples*/ + return (ms * 0.001f) * samplerate; +} + +float GranularPlayer::NegativeInvert(Phasor* phs, float frequency) +{ + /*inverts the phase of the phasor if the frequency is negative, mimicking pure data's phasor~ object*/ + return (frequency > 0) ? phs->Process() : ((phs->Process() * -1) + 1); +} + +float GranularPlayer::Process(float speed, + float transposition, + float grain_size) +{ + grain_size_ = grain_size; + speed_ = speed * sample_frequency_; + transposition_ = (CentsToRatio(transposition) - speed) + * (grain_size >= 1 ? 1000 / grain_size_ : 1); + phs_.SetFreq(fabs((speed_ / 2))); + phs2_.SetFreq(fabs((speed_ / 2))); + phsImp_.SetFreq(fabs(transposition_)); + phsImp2_.SetFreq(fabs(transposition_)); + idxSpeed_ = NegativeInvert(&phs_, speed_) * size_; + idxSpeed2_ = NegativeInvert(&phs2_, speed_) * size_; + idxTransp_ = (NegativeInvert(&phsImp_, transposition_) + * MsToSamps(grain_size_, sample_rate_)); + idxTransp2_ = (NegativeInvert(&phsImp2_, transposition_) + * MsToSamps(grain_size_, sample_rate_)); + idx_ = WrapIdx((uint32_t)(idxSpeed_ + idxTransp_), size_); + idx2_ = WrapIdx((uint32_t)(idxSpeed2_ + idxTransp2_), size_); + sig_ = sample_[idx_] * cosEnv_[(uint32_t)(phs_.Process() * 256)]; + sig2_ = sample_[idx2_] * cosEnv_[(uint32_t)(phs2_.Process() * 256)]; + return (sig_ + sig2_) / 2; +} \ No newline at end of file diff --git a/Source/Sampling/granularplayer.h b/Source/Sampling/granularplayer.h new file mode 100644 index 00000000..7f49f4d5 --- /dev/null +++ b/Source/Sampling/granularplayer.h @@ -0,0 +1,88 @@ +#pragma once +#ifndef DSY_GRANULARPLAYER_H +#define DSY_GRANULARPLAYER_H + +#include +#include +#include "Control/phasor.h" +#ifdef __cplusplus +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif + +namespace daisysp +{ +/** GranularPlayer Module + + Date: November, 2023 + + Author: Vinícius Fernandes + + GranularPlayer is a lookup table player that provides independent time stretching and pitch shifting + via granulation. + Inspired by the grain.player object from else pure data's library. +*/ + +class GranularPlayer +{ + public: + GranularPlayer() {} + ~GranularPlayer() {} + + /** Initializes the GranularPlayer module. + \param sample pointer to the sample to be played + \param size number of elements in the sample array + \param sample_rate audio engine sample rate + */ + void Init(float* sample, int size, float sample_rate); + + /** Processes the granular player. + \param speed playback speed. 1 is normal speed, 2 is double speed, 0.5 is half speed, etc. Negative values play the sample backwards. + \param transposition transposition in cents. 100 cents is one semitone. Negative values transpose down, positive values transpose up. + \param grain_size grain size in milliseconds. 1 is 1 millisecond, 1000 is 1 second. Does not accept negative values. Minimum value is 1. + */ + float Process(float speed, float transposition, float grain_size); + + private: + //Wraps an index to the size of the sample array + uint32_t WrapIdx(uint32_t idx, uint32_t size); + + //Converts cents(1/100th of a semitone) to a ratio + float CentsToRatio(float cents); + + //Converts milliseconds to number of samples + float MsToSamps(float ms, float samplerate); + + //Inverts the phase of the phasor if the frequency is negative, mimicking pure data's phasor~ object + float NegativeInvert(Phasor* phs, float frequency); + + + float* sample_; //pointer to the sample to be played + float sample_rate_; //audio engine sample rate + int size_; //number of elements in the sample array + float grain_size_; //grain size in milliseconds + float speed_; //processed playback speed. + float transposition_; //processed transpotion. + float sample_frequency_; + float cosEnv_[256] = {0}; //cosine envelope for crossfading between grains + float + idxTransp_; // Adjusted Transposition value contribution to idx of first grain + float + idxTransp2_; // Adjusted Transposition value contribution to idx of second grain + float idxSpeed_; // Adjusted Speed value contribution to idx of first grain + float + idxSpeed2_; // Adjusted Speed value contribution to idx of second grain + float sig_; // Output of first grain + float sig2_; // Output of second grain + + uint32_t idx_; // Index of first grain + uint32_t idx2_; // Index of second grain + + Phasor phs_; // Phasor for speed + Phasor phsImp_; // Phasor for transposition + Phasor phs2_; // Phasor for speed + Phasor phsImp2_; // Phasor for transposition +}; +} // namespace daisysp +#endif +#endif \ No newline at end of file diff --git a/Source/daisysp.h b/Source/daisysp.h index e5a92cdc..aa351e16 100644 --- a/Source/daisysp.h +++ b/Source/daisysp.h @@ -79,6 +79,9 @@ #include "PhysicalModeling/KarplusString.h" #include "PhysicalModeling/stringvoice.h" +/** Sampling Modules */ +#include "Sampling/granularplayer.h" + /** Synthesis Modules */ #include "Synthesis/blosc.h" #include "Synthesis/fm2.h" From e0ad5e6a10130291ba62d9ee46216e41a9687196 Mon Sep 17 00:00:00 2001 From: beserge Date: Mon, 11 Dec 2023 15:23:47 -0500 Subject: [PATCH 2/2] Fix Granular Player style --- Source/Sampling/granularplayer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source/Sampling/granularplayer.h b/Source/Sampling/granularplayer.h index 7f49f4d5..e59c1e09 100644 --- a/Source/Sampling/granularplayer.h +++ b/Source/Sampling/granularplayer.h @@ -68,12 +68,12 @@ class GranularPlayer float idxTransp_; // Adjusted Transposition value contribution to idx of first grain float - idxTransp2_; // Adjusted Transposition value contribution to idx of second grain + idxTransp2_; // Adjusted Transposition value contribution to idx of second grain float idxSpeed_; // Adjusted Speed value contribution to idx of first grain float - idxSpeed2_; // Adjusted Speed value contribution to idx of second grain - float sig_; // Output of first grain - float sig2_; // Output of second grain + idxSpeed2_; // Adjusted Speed value contribution to idx of second grain + float sig_; // Output of first grain + float sig2_; // Output of second grain uint32_t idx_; // Index of first grain uint32_t idx2_; // Index of second grain