SAF
Loading...
Searching...
No Matches
pitch_shifter.c
Go to the documentation of this file.
1/*
2 * Copyright 2020 Leo McCormack
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
13 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
25
26#include "pitch_shifter.h"
28
30(
31 void ** const phPS
32)
33{
35 *phPS = (void*)pData;
36
37 /* Default user parameters */
38 pData->new_nChannels = pData->nChannels = 1;
39 pData->pitchShift_factor = 1.0f;
40 pData->osamp_option = PITCH_SHIFTER_OSAMP_4;
41 pData->fftsize_option = PITCH_SHIFTER_FFTSIZE_4096;
42
43 /* internals */
44 pData->hSmb = NULL;
45 pData->progressBar0_1 = 0.0f;
47 strcpy(pData->progressBarText,"");
48 pData->sampleRate = 0.0f;
49 pData->fftFrameSize = 4096; /* Not important to get right, as it will be overwritten upon init */
50 pData->stepsize = 1024; /* same here */
51
52 /* flags */
55
56 /* set FIFO buffers */
57 pData->sampleRate = 48000.0f;
58 pData->firstInit = 1;
59 pData->FIFO_idx = 0;
60 pData->inFIFO = (float**)calloc2d(MAX_NUM_CHANNELS, PITCH_SHIFTER_FRAME_SIZE, sizeof(float));
61 pData->outFIFO = (float**)calloc2d(MAX_NUM_CHANNELS, PITCH_SHIFTER_FRAME_SIZE, sizeof(float));
62 //memset(FLATTEN2D(pData->inFIFO), 0, MAX_NUM_CHANNELS*PITCH_SHIFTER_FRAME_SIZE*sizeof(float));
63 //memset(FLATTEN2D(pData->outFIFO), 0, MAX_NUM_CHANNELS*PITCH_SHIFTER_FRAME_SIZE*sizeof(float));
64}
65
67(
68 void ** const phPS
69)
70{
71 pitch_shifter_data *pData = (pitch_shifter_data*)(*phPS);
72
73 if (pData != NULL) {
74 /* not safe to free memory during intialisation/processing loop */
75 while (pData->codecStatus == CODEC_STATUS_INITIALISING ||
77 SAF_SLEEP(10);
78 }
79
80 if (pData->hSmb != NULL)
82 free(pData->inFIFO);
83 free(pData->outFIFO);
84 free(pData);
85 pData = NULL;
86 *phPS = NULL;
87 }
88}
89
91(
92 void * const hPS,
93 int sampleRate
94)
95{
97
98 if(pData->sampleRate != (float)sampleRate || pData->firstInit){
99 pData->sampleRate = (float)sampleRate;
101 pData->firstInit = 0;
102 }
103}
104
106(
107 void* const hPS
108)
109{
110 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
111 int nChannels, fftSize, osamp;
112
114 return; /* re-init not required, or already happening */
115 while (pData->procStatus == PROC_STATUS_ONGOING){
116 /* re-init required, but we need to wait for the current processing loop to end */
117 pData->codecStatus = CODEC_STATUS_INITIALISING; /* indicate that we want to init */
118 SAF_SLEEP(10);
119 }
120
121 /* for progress bar */
123 strcpy(pData->progressBarText,"Initialising pitch shifter");
124 pData->progressBar0_1 = 0.0f;
125
126 nChannels = pData->new_nChannels;
127
128 /* destroy current handle*/
129 if (pData->hSmb != NULL)
130 smb_pitchShift_destroy(&(pData->hSmb));
131
132 /* Config */
133
134 PITCH_SHIFTER_OSAMP_OPTIONS osamp_option = pData->osamp_option;
135 switch(osamp_option){
136 default:
137 /* fall through */
138 case PITCH_SHIFTER_OSAMP_2: osamp = 2; break;
139 case PITCH_SHIFTER_OSAMP_4: osamp = 4; break;
140 case PITCH_SHIFTER_OSAMP_8: osamp = 8; break;
141 case PITCH_SHIFTER_OSAMP_16: osamp = 16; break;
142 case PITCH_SHIFTER_OSAMP_32: osamp = 32; break;
143 }
144 PITCH_SHIFTER_FFTSIZE_OPTIONS fftsize_option = pData->fftsize_option;
145 switch(fftsize_option){
146 default:
147 /* fall through */
148 case PITCH_SHIFTER_FFTSIZE_512: fftSize = 512; break;
149 case PITCH_SHIFTER_FFTSIZE_1024: fftSize = 1024; break;
150 case PITCH_SHIFTER_FFTSIZE_2048: fftSize = 2048; break;
151 case PITCH_SHIFTER_FFTSIZE_4096: fftSize = 4096; break;
152 case PITCH_SHIFTER_FFTSIZE_8192: fftSize = 8192; break;
153 case PITCH_SHIFTER_FFTSIZE_16384: fftSize = 16384; break;
154 }
155 pData->fftFrameSize = fftSize;
156 pData->stepsize = fftSize/osamp;
157
158 /* Create new handle */
159 smb_pitchShift_create(&(pData->hSmb), nChannels, fftSize, osamp, pData->sampleRate);
160 pData->nChannels = nChannels;
161
162 /* done! */
163 strcpy(pData->progressBarText,"Done!");
164 pData->progressBar0_1 = 1.0f;
166}
167
169(
170 void * const hPS,
171 const float *const * inputs,
172 float* const* const outputs,
173 int nInputs,
174 int nOutputs,
175 int nSamples
176)
177{
178 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
179 int s, ch, nChannels;
180 nChannels = pData->nChannels;
181
182 /* Loop over all samples */
183 for(s=0; s<nSamples; s++){
184 /* Load input signals into inFIFO buffer */
185 for(ch=0; ch<SAF_MIN(nInputs,nChannels); ch++)
186 pData->inFIFO[ch][pData->FIFO_idx] = inputs[ch][s];
187 for(; ch<nChannels; ch++) /* Zero any channels that were not given */
188 pData->inFIFO[ch][pData->FIFO_idx] = 0.0f;
189
190 /* Pull output signals from outFIFO buffer */
191 for(ch=0; ch<SAF_MIN(nOutputs, nChannels); ch++)
192 outputs[ch][s] = pData->outFIFO[ch][pData->FIFO_idx];
193 for(; ch<nOutputs; ch++) /* Zero any extra channels */
194 outputs[ch][s] = 0.0f;
195
196 /* Increment buffer index */
197 pData->FIFO_idx++;
198
199 /* Process frame if inFIFO is full and codec is ready for it */
201 pData->FIFO_idx = 0;
203
204 /* load input */
205 for(ch=0; ch<nChannels; ch++)
206 memcpy(pData->inputFrame[ch], pData->inFIFO[ch], PITCH_SHIFTER_FRAME_SIZE*sizeof(float));
207
208 /* Apply pitch shifting */
209 smb_pitchShift_apply(pData->hSmb, pData->pitchShift_factor, PITCH_SHIFTER_FRAME_SIZE, (float*)pData->inputFrame, (float*)pData->outputFrame);
210
211 /* Copy to output */
212 for(ch=0; ch<nChannels; ch++)
213 memcpy(pData->outFIFO[ch], pData->outputFrame[ch], PITCH_SHIFTER_FRAME_SIZE*sizeof(float));
214 }
215 else if(pData->FIFO_idx >= PITCH_SHIFTER_FRAME_SIZE){
216 /* clear outFIFO if codec was not ready */
217 pData->FIFO_idx = 0;
218 memset(FLATTEN2D(pData->outFIFO), 0, MAX_NUM_CHANNELS*PITCH_SHIFTER_FRAME_SIZE*sizeof(float));
219 }
220 }
221
223}
224
225/* sets */
226
231
232void pitch_shifter_setPitchShiftFactor(void* const hPS, float newValue)
233{
234 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
235 pData->pitchShift_factor = newValue;
236}
237
238void pitch_shifter_setNumChannels(void* const hPS, int newValue)
239{
240 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
241 pData->new_nChannels = newValue;
243}
244
246(
247 void* const hPS,
249)
250{
251 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
252 pData->fftsize_option = newOption;
254}
255
257(
258 void* const hPS,
260)
261{
262 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
263 pData->osamp_option = newOption;
265}
266
267
268/* gets */
269
274
276{
277 pitch_shifter_data *pData = (pitch_shifter_data*)(hBin);
278 return pData->codecStatus;
279}
280
281float pitch_shifter_getProgressBar0_1(void* const hBin)
282{
283 pitch_shifter_data *pData = (pitch_shifter_data*)(hBin);
284 return pData->progressBar0_1;
285}
286
287void pitch_shifter_getProgressBarText(void* const hBin, char* text)
288{
289 pitch_shifter_data *pData = (pitch_shifter_data*)(hBin);
290 memcpy(text, pData->progressBarText, PROGRESSBARTEXT_CHAR_LENGTH*sizeof(char));
291}
292
294{
295 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
296 return pData->pitchShift_factor;
297}
298
304
306{
307 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
308 return pData->osamp_option;
309}
310
312{
313 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
314 return pData->new_nChannels;
315}
316
318{
319 pitch_shifter_data *pData = (pitch_shifter_data*)(hPS);
320 return PITCH_SHIFTER_FRAME_SIZE + pData->fftFrameSize - (pData->stepsize);
321}
322
#define MAX_NUM_CHANNELS
Maximum number of input/output channels supported.
Definition _common.h:258
#define PROGRESSBARTEXT_CHAR_LENGTH
Length of progress bar string.
Definition _common.h:255
@ PROC_STATUS_ONGOING
Codec is processing input audio, and should not be reinitialised at this time.
Definition _common.h:248
@ PROC_STATUS_NOT_ONGOING
Codec is not processing input audio, and may be reinitialised if needed.
Definition _common.h:250
CODEC_STATUS
Current status of the codec.
Definition _common.h:229
@ CODEC_STATUS_NOT_INITIALISED
Codec has not yet been initialised, or the codec configuration has changed.
Definition _common.h:232
@ CODEC_STATUS_INITIALISED
Codec is initialised and ready to process input audio.
Definition _common.h:230
@ CODEC_STATUS_INITIALISING
Codec is currently being initialised, input audio should not be processed.
Definition _common.h:235
void smb_pitchShift_create(void **hSmb, int nCH, int fftFrameSize, int osamp, float sampleRate)
Creates an instance of SMB PitchShifter.
void smb_pitchShift_apply(void *hSmb, float pitchShift, int frameSize, float *indata, float *outdata)
Performs pitch shifting of the input signals, while retaining the same time duration as the original ...
void smb_pitchShift_destroy(void **const hSmb)
Destroys an instance of SMB PitchShifter.
#define SAF_MIN(a, b)
Returns the minimum of the two values.
void * malloc1d(size_t dim1_data_size)
1-D malloc (same as malloc, but with error checking)
Definition md_malloc.c:59
void ** calloc2d(size_t dim1, size_t dim2, size_t data_size)
2-D calloc (contiguously allocated, so use free() as usual to deallocate)
Definition md_malloc.c:102
#define FLATTEN2D(A)
Use this macro when passing a 2-D dynamic multi-dimensional array to memset, memcpy or any other func...
Definition md_malloc.h:65
void pitch_shifter_setOSampOption(void *const hPS, PITCH_SHIFTER_OSAMP_OPTIONS newOption)
Sets the oversampling factor used by the algorithm (see PITCH_SHIFTER_OSAMP_OPTIONS enum)
void pitch_shifter_setPitchShiftFactor(void *const hPS, float newValue)
Sets the pitch shift factor, 1: no change, 2: up one octave, 0.5: down one octave.
CODEC_STATUS pitch_shifter_getCodecStatus(void *const hBin)
Returns current codec status (see CODEC_STATUS enum)
void pitch_shifter_create(void **const phPS)
Creates an instance of pitch_shifter.
int pitch_shifter_getProcessingDelay(void *const hPS)
Returns the processing delay in samples (may be used for delay compensation features)
void pitch_shifter_setFFTSizeOption(void *const hPS, PITCH_SHIFTER_FFTSIZE_OPTIONS newOption)
Sets the FFT size used by the algorithm (see PITCH_SHIFTER_FFTSIZE_OPTIONS enum)
void pitch_shifter_destroy(void **const phPS)
Destroys an instance of pitch_shifter.
void pitch_shifter_initCodec(void *const hPS)
Intialises the codec variables, based on current global/user parameters.
int pitch_shifter_getNCHrequired(void *const hPS)
Returns the number of channels required by the current configuration.
float pitch_shifter_getPitchShiftFactor(void *const hPS)
Returns the pitch shift factor, 1: no change, 2: up one octave, 0.5: down one octave.
PITCH_SHIFTER_OSAMP_OPTIONS pitch_shifter_getOSampOption(void *const hPS)
Returns the oversampling factor used by the algorithm (see PITCH_SHIFTER_OSAMP_OPTIONS enum)
float pitch_shifter_getProgressBar0_1(void *const hBin)
(Optional) Returns current intialisation/processing progress, between 0..1
PITCH_SHIFTER_FFTSIZE_OPTIONS pitch_shifter_getFFTSizeOption(void *const hPS)
Returns the FFT size used by the algorithm (see PITCH_SHIFTER_FFTSIZE_OPTIONS enum)
void pitch_shifter_process(void *const hPS, const float *const *inputs, float *const *const outputs, int nInputs, int nOutputs, int nSamples)
Pitch shifts the input signals.
void pitch_shifter_getProgressBarText(void *const hBin, char *text)
(Optional) Returns current intialisation/processing progress text
int pitch_shifter_getFrameSize(void)
Returns the processing framesize (i.e., number of samples processed with every _process() call )
void pitch_shifter_init(void *const hPS, int sampleRate)
Initialises an instance of pitch_shifter with default settings.
void pitch_shifter_setNumChannels(void *const hPS, int newValue)
Sets the number channels to pitch shift.
void pitch_shifter_refreshParams(void *const hPS)
Sets all intialisation flags to 1; re-initialising all settings/variables as pitch_shifter is current...
A very basic multichannel pitch shifter.
PITCH_SHIFTER_FFTSIZE_OPTIONS
Available FFT size options.
PITCH_SHIFTER_OSAMP_OPTIONS
Available oversampling options.
void pitch_shifter_setCodecStatus(void *const hPS, CODEC_STATUS newStatus)
Sets codec status (see CODEC_STATUS enum)
A very basic multichannel pitch shifter.
#define PITCH_SHIFTER_FRAME_SIZE
Framesize, in time-domain samples.
Main struct for the pitch_shifter.
float inputFrame[MAX_NUM_CHANNELS][PITCH_SHIFTER_FRAME_SIZE]
Current input frame.
float outputFrame[MAX_NUM_CHANNELS][PITCH_SHIFTER_FRAME_SIZE]
Current output frame.
_Atomic_PROC_STATUS procStatus
see PROC_STATUS
_Atomic_FLOAT32 progressBar0_1
Current (re)initialisation progress, between [0..1].
float ** inFIFO
Input FIFO buffer.
_Atomic_PITCH_SHIFTER_FFTSIZE_OPTIONS fftsize_option
see PITCH_SHIFTER_FFTSIZE_OPTIONS
_Atomic_FLOAT32 pitchShift_factor
1: no shift, 0.5: down one octave, 2: up one octave
_Atomic_INT32 nChannels
Current number of input/output channels.
_Atomic_CODEC_STATUS codecStatus
see CODEC_STATUS
char * progressBarText
Current (re)initialisation step, string.
int FIFO_idx
FIFO buffer index.
int stepsize
Hop size in samples.
_Atomic_PITCH_SHIFTER_OSAMP_OPTIONS osamp_option
see PITCH_SHIFTER_OSAMP_OPTIONS
void * hSmb
pitch-shifter handle
float ** outFIFO
Output FIFO buffer.
int firstInit
flag, 1: _init() function has never been called, 0: _init() function has been called
float sampleRate
Host sampling rate, in Hz.
_Atomic_INT32 new_nChannels
(current value will be replaced by this after next re-init)