Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions Sources/CSoundpipeAudioKit/Generators/PhaseLockedVocoderDSP.mm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "SoundpipeDSPBase.h"
#include "ParameterRamper.h"
#include "Soundpipe.h"
#include "CSoundpipeAudioKit.h"
#include <vector>

enum PhaseLockedVocoderParameter : AUParameterAddress {
Expand All @@ -16,6 +17,7 @@
sp_mincer *mincer;
sp_ftbl *ftbl;
std::vector<float> wavetable;
int mincerSize = 2048;

ParameterRamper positionRamp;
ParameterRamper amplitudeRamp;
Expand All @@ -42,7 +44,7 @@ void init(int channelCount, double sampleRate) override {
sp_ftbl_create(sp, &ftbl, wavetable.size());
std::copy(wavetable.cbegin(), wavetable.cend(), ftbl->tbl);
sp_mincer_create(&mincer);
sp_mincer_init(sp, mincer, ftbl, 2048);
sp_mincer_init(sp, mincer, ftbl, mincerSize);
}

void deinit() override {
Expand All @@ -56,7 +58,12 @@ void reset() override {
if (!isInitialized) return;
sp_mincer_destroy(&mincer);
sp_mincer_create(&mincer);
sp_mincer_init(sp, mincer, ftbl, 2048);
sp_mincer_init(sp, mincer, ftbl, mincerSize);
}

void setMincerSize(int size) {
mincerSize = size;
reset();
}

void process(FrameRange range) override {
Expand All @@ -73,6 +80,12 @@ void process(FrameRange range) override {
}
};

void akPhaseLockedVocoderSetMincerSize(DSPRef dspRef, int size) {
auto dsp = dynamic_cast<PhaseLockedVocoderDSP *>(dspRef);
assert(dsp);
dsp->setMincerSize(size);
}

AK_REGISTER_DSP(PhaseLockedVocoderDSP, "minc")
AK_REGISTER_PARAMETER(PhaseLockedVocoderParameterPosition)
AK_REGISTER_PARAMETER(PhaseLockedVocoderParameterAmplitude)
Expand Down
3 changes: 2 additions & 1 deletion Sources/CSoundpipeAudioKit/include/CSoundpipeAudioKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ void akCombFilterReverbSetLoopDuration(DSPRef dsp, float duration);
void akConvolutionSetPartitionLength(DSPRef dsp, int length);
void akFlatFrequencyResponseSetLoopDuration(DSPRef dsp, float duration);
void akVariableDelaySetMaximumTime(DSPRef dsp, float maximumTime);
CF_EXTERN_C_END
void akPhaseLockedVocoderSetMincerSize(DSPRef dspRef, int size);
CF_EXTERN_C_END
23 changes: 22 additions & 1 deletion Sources/SoundpipeAudioKit/Generators/PhaseLockedVocoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import AudioKit
import AudioKitEX
import AVFoundation
import CAudioKitEX
import CSoundpipeAudioKit

/// This is a phase locked vocoder. It has the ability to play back an audio
/// file loaded into an ftable like a sampler would. Unlike a typical sampler,
Expand Down Expand Up @@ -69,16 +70,36 @@ public class PhaseLockedVocoder: Node {
file: AVAudioFile,
position: AUValue = positionDef.defaultValue,
amplitude: AUValue = amplitudeDef.defaultValue,
pitchRatio: AUValue = pitchRatioDef.defaultValue
pitchRatio: AUValue = pitchRatioDef.defaultValue,
grainSize: Int32 = 2048
) {
setupParameters()

loadFile(file)

let safeGrainSize = roundUpToPowerOfTwo(grainSize)
akPhaseLockedVocoderSetMincerSize(au.dsp, safeGrainSize)

self.position = position
self.amplitude = amplitude
self.pitchRatio = pitchRatio
}

/// The grain size range is 128 - 8192 and it must be a power of two.
/// If it isn't one already, this function will round it up to the next power of two
/// (should we warn the user if they submit a value which is not in that range or is not a power of two?)
func roundUpToPowerOfTwo(_ value: Int32) -> Int32 {
let range: ClosedRange<Int32> = 128...8192
guard range.contains(value) else { return min(max(value, range.lowerBound), range.upperBound) }
var result = value - 1
result |= result >> 1
result |= result >> 2
result |= result >> 4
result |= result >> 8
result |= result >> 16
result += 1
return result
}

/// Call this function after you are done with the node, to reset the au wavetable to prevent memory leaks
public func dispose() {
Expand Down
Loading