-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #194 from viniciusfersil123/granular_player
feat: adds new granular player module and sampling folder
- Loading branch information
Showing
5 changed files
with
177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#pragma once | ||
#ifndef DSY_GRANULARPLAYER_H | ||
#define DSY_GRANULARPLAYER_H | ||
|
||
#include <stdint.h> | ||
#include <cmath> | ||
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters