Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,6 @@ vcpkg_installed/
# test output & cache
Testing/
.cache/

# don't need the vscode settings folder
.vscode
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file (and the other CMakeLists.txt files in this repo)
# are adapted from the prototype CMakeLists.txt provided with the SuperCollider plugin starter code.

cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.20)
project(flexplugins)

# To make a ZIP archive
Expand Down Expand Up @@ -124,13 +124,17 @@ install(FILES
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
install(FILES
src/generators/ImpulseDropout.schelp
src/generators/ImpulseJitter.schelp
src/generators/LoopPhasor.schelp
src/pv/PV_CFreeze.schelp
src/pv/PV_MagMirror.schelp
src/pv/PV_MagSqueeze.schelp
src/pv/PV_PlayBufStretch.schelp
src/pv/PV_MagXFade.schelp
src/rubberband/RubberBandPS.schelp
src/rubberband/RubberBandStretcher.schelp
src/rubberband/RubberBandStretcherBuf.schelp
DESTINATION HelpSource/Classes
PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ
)
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ A collection of SuperCollider plugins developed by Jeff Martin (www.jeffreymarti

## List of Plugins

### LoopPhasor
LoopPhasor is an adaptation of Phasor, which allows you to set loop points. It is useful for playing audio samples for which you can define loop points.
### PV_PlayBufStretch
A phase vocoder STFT buffer player for time stretching, for use with PV_RecordBuf in the sc3plugins distribution. It incorporates two different optional phase locking algorithms.

### PV_CFreeze
A SuperCollider implementation of Jean-François Charles' Max patch for freezing [(the Max patch is available here)](https://newfloremusic.gumroad.com/).
It is a phase vocoder spectral freeze with an innovation that makes the frozen sound less stagnant.

### PV_MagMirror
Mirrors spectral magnitudes, so that high magnitudes become low and low magnitudes become high.

### PV_MagSqueeze
Squeezes spectral magnitudes to fit between (low, high).

Expand All @@ -22,6 +25,18 @@ A formant-preserving phase vocoder pitch shifter using the [RubberBand library](
### RubberBandStretcher
A phase vocoder pitch shifter and time stretcher using the [RubberBand library](https://breakfastquay.com/rubberband/).

### RubberBandStretcherBuf
A phase vocoder pitch shifter and time stretcher using the [RubberBand library](https://breakfastquay.com/rubberband/). This version writes the stretched audio to a buffer rather than outputting it directly.

### ImpulseDropout
A modified version of Impulse that randomly drops a percentage of impulses, producing a stuttering effect.

### ImpulseJitter
A modified version of Impulse that allows the impulses to be shifted randomly in time. It allows a steady move between regular and chaotic impulses, which can be useful for event triggers.

### LoopPhasor
An adaptation of Phasor, which allows you to set loop start and stop points. It is useful for playing audio samples for which you can define loop points.

## To Install
You can download a compiled version of the plugins from Releases in this repository.
Extract the ZIP file and copy its contents to your SuperCollider extensions directory
Expand Down
19 changes: 19 additions & 0 deletions src/generators/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,27 @@
# Create the project library
add_library(generators MODULE generators.cpp)
add_library(arrayHeap STATIC arrayheap.cpp)
add_library(loopPhasor STATIC loopPhasor.cpp)
add_library(impulseDropout STATIC impulseDropout.cpp)
add_library(impulseJitter STATIC impulseJitter.cpp)
set_target_properties(arrayHeap PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(loopPhasor PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(impulseDropout PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(impulseJitter PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(generators PRIVATE
loopPhasor
impulseDropout
impulseJitter
)
target_link_libraries(impulseJitter PRIVATE arrayHeap)

if(SUPERNOVA)
add_library(generators_supernova MODULE generators.cpp)
set_property(TARGET generators_supernova
PROPERTY COMPILE_DEFINITIONS SUPERNOVA)
target_link_libraries(generators_supernova PRIVATE
loopPhasor
impulseDropout
impulseJitter
)
endif()
50 changes: 50 additions & 0 deletions src/generators/ImpulseDropout.schelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
class:: ImpulseDropout
summary:: Modified Impulse with dropout
related:: Classes/Impulse, Classes/Dust
categories:: Libraries>FlexUGens, UGens>Generators>Stochastic


Description::

ImpulseDropout is a modified version of Impulse that randomly drops a percentage of impulses,
controlled by the dropFrac argument. For example, if dropFrac = 0.2, 0.2 of the impulses
will be zeroed out per audio block. The impulses that are zeroed out are chosen randomly.

classmethods::

method::ar, kr

argument::freq
Frequency in Hertz. freq may be negative.

argument::phase
Phase offset in cycles (0..1). Staying in this range offers a slight efficiency advantage,
though phase offsets outside this range are supported and wrapped internally.

argument::dropFrac
The percentage of impulses that will be randomly dropped (between 0.0 and 1.0).
Values greater than or equal to 1.0 result in silence (all impulses are dropped),
and values less than or equal to 0.0 produce the same output as the Impulse UGen.

argument::mul
The output will be multiplied by this value.

argument::add
This value will be added to the output.

Examples::

code::
(
SynthDef(\dropout, {
arg freq, dropFrac, amp;
var sig;
sig = ImpulseDropout.ar(freq, 0.0, dropFrac, amp);
sig = LPF.ar(sig, freq);
sig = LeakDC.ar(sig);
Out.ar(0, sig);
}).add;

Synth(\dropout, [\freq, 440.0, \dropFrac, 0.4, \amp, -12.dbamp]);
)
::
48 changes: 48 additions & 0 deletions src/generators/ImpulseJitter.schelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
class:: ImpulseJitter
summary:: Modified Impulse with jitter
related:: Classes/Impulse, Classes/Dust
categories:: Libraries>FlexUGens, UGens>Generators>Stochastic


Description::

ImpulseJitter is a modified version of Impulse that adds some jitter to each impulse position,
controlled by the jitterFrac argument. For example, if jitterFrac = 0.2, each impulse can be
randomly shifted in time by up to 0.2 of the block size.

classmethods::

method::ar, kr

argument::freq
Frequency in Hertz. freq may be negative.

argument::phase
Phase offset in cycles (0..1). Staying in this range offers a slight efficiency advantage,
though phase offsets outside this range are supported and wrapped internally.

argument::jitterFrac
The maximum fraction of the block size to allow for jitter.

argument::mul
The output will be multiplied by this value.

argument::add
This value will be added to the output.

Examples::

code::
(
SynthDef(\jitter, {
arg freq, jitterFrac, amp;
var sig;
sig = ImpulseJitter.ar(freq, 0.0, jitterFrac, amp);
sig = LPF.ar(sig, freq);
sig = LeakDC.ar(sig);
Out.ar(0, sig);
}).add;

Synth(\jitter, [\freq, 440.0, \jitterFrac, 0.1, \amp, -12.dbamp]);
)
::
106 changes: 106 additions & 0 deletions src/generators/arrayheap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
File: arrayheap.cpp
Author: Jeff Martin

Description:
A simple array-based heap

Copyright © 2025 by Jeffrey Martin. All rights reserved.
Website: https://www.jeffreymartincomposer.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#include "arrayheap.hpp"

// Inserts into the heap
int heapInsert(IntMinHeap* heap, int data) {
if (heap->size == heap->maxSize) {
return 0;
} else {
if (heap->size == 0) {
heap->size++;
}
size_t idx = heap->size;
heap->heap[idx] = data;
heap->size++;

// Bubble up
while (idx > 1) {
size_t parentIdx = idx;
if (parentIdx % 2 == 1)
parentIdx--;
parentIdx >>= 1;
if (heap->heap[idx] < heap->heap[parentIdx]) {
int swapVal = heap->heap[idx];
heap->heap[idx] = heap->heap[parentIdx];
heap->heap[parentIdx] = swapVal;
}
idx = parentIdx;
}
return 1;
}
}

// Removes from the heap and returns the value popped. Returns 0 if the heap is empty.
int heapPop(IntMinHeap* heap) {
if (heap->size > 1) {
int val = heap->heap[1];
heap->heap[1] = heap->heap[heap->size-1];
heap->size--;
size_t idx = 1;
// Bubble down
while (idx < heap->size) {
size_t leftChild = idx * 2;
size_t rightChild = leftChild + 1;
if (rightChild < heap->size) {
if (heap->heap[leftChild] <= heap->heap[rightChild] && heap->heap[idx] > heap->heap[leftChild]) {
int swapVal = heap->heap[leftChild];
heap->heap[leftChild] = heap->heap[idx];
heap->heap[idx] = swapVal;
idx = leftChild;
} else if (heap->heap[leftChild] > heap->heap[rightChild] && heap->heap[idx] > heap->heap[rightChild]) {
int swapVal = heap->heap[rightChild];
heap->heap[rightChild] = heap->heap[idx];
heap->heap[idx] = swapVal;
idx = rightChild;
} else {
break;
}
} else if (leftChild < heap->size) {
if (heap->heap[idx] > heap->heap[leftChild]) {
int swapVal = heap->heap[leftChild];
heap->heap[leftChild] = heap->heap[idx];
heap->heap[idx] = swapVal;
idx = leftChild;
}
break;
} else {
break;
}
}
return val;
} else {
return 0;
}
}

// Safe peek at the top of the heap
int heapPeek(IntMinHeap* heap) {
if (heap->size > 1) {
return heap->heap[1];
} else {
return -1;
}
}
42 changes: 42 additions & 0 deletions src/generators/arrayheap.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
File: arrayheap.hpp
Author: Jeff Martin

Description:
A simple array-based heap

Copyright © 2025 by Jeffrey Martin. All rights reserved.
Website: https://www.jeffreymartincomposer.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once
#include <cstddef>

/// A min heap for ints.
typedef struct {
int* heap;
size_t size;
size_t maxSize;
} IntMinHeap;

/// Inserts into the heap
int heapInsert(IntMinHeap* heap, int data);

/// Removes from the heap and returns the value popped. Returns 0 if the heap is empty.
int heapPop(IntMinHeap* heap);

/// Safe peek at the top of the heap
int heapPeek(IntMinHeap* heap);
Loading
Loading