Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to merge back changes from SuperDough fork #303

Open
wants to merge 34 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b0dce42
fixed amp
daslyfe Aug 18, 2024
fc4c24f
clip
daslyfe Aug 18, 2024
e58583e
adjusted envelope behavior
daslyfe Aug 20, 2024
789eace
lp envelope
daslyfe Aug 20, 2024
42b282f
feat: filter envelope
daslyfe Aug 23, 2024
d0c7fcb
working on supersaw
daslyfe Aug 25, 2024
7b768d0
simplifying supersaw
daslyfe Aug 27, 2024
c0e7366
supersaw finally
daslyfe Aug 29, 2024
9b85220
fixed scale ration of samples
daslyfe Aug 30, 2024
04bd40a
need fix...
daslyfe Aug 30, 2024
88bfe27
flix clip duration
daslyfe Aug 30, 2024
e6350ab
add distortion
daslyfe Aug 30, 2024
e60f514
update doc
daslyfe Aug 30, 2024
7a0e601
fix stupid null handling bug with supersaw :)
daslyfe Aug 30, 2024
cbbe8ba
fix sound order
daslyfe Aug 31, 2024
cda96c6
fix release sample repeat bug and sample clipping behavior
daslyfe Aug 31, 2024
fd6c624
add remaining filter envelopes
daslyfe Aug 31, 2024
36be99b
kinda working
daslyfe Sep 1, 2024
368613d
phaser and compressor
daslyfe Sep 2, 2024
f32c1b9
fix phaser
daslyfe Sep 2, 2024
561903a
phase_depth_min
daslyfe Sep 3, 2024
7072d23
add noise
daslyfe Sep 3, 2024
2859c80
add pulse oscillator
daslyfe Sep 6, 2024
287947f
superpulse
daslyfe Sep 7, 2024
266b616
fix: gain staging
daslyfe Sep 8, 2024
1becbcc
add non sc3 feedback delay with filtering
daslyfe Sep 8, 2024
a47e9ff
feat: shimmer delay
daslyfe Sep 9, 2024
c96ef2a
feat: juno chorus
daslyfe Sep 9, 2024
bcf605e
fix chorus stereo imaging
daslyfe Sep 9, 2024
b114473
fix reverb and delay send behavior
daslyfe Sep 11, 2024
48d2bad
fix volume normalization
daslyfe Sep 13, 2024
019c1ba
first synthkick
daslyfe Sep 17, 2024
ad53027
feat: limiter gain, wet gain, dry gain
daslyfe Oct 13, 2024
e9ab9d9
updated readme
daslyfe Oct 13, 2024
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
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,21 @@
# SuperDirt
# SuperTweak
This is a fork of superdirt that is intended to play well with Strudel.cc
The intention of the fork is to be temporary, as features are planned to be merged back into superdirt over time. Features:
- note scaling is the same as Strudel
- Shimmer Reverb effect ".shimmer(1)"
- new oscillator types: supersaw, superpulse, sawtooth, triangle, pulse
- z parameters AKA oscillator macros z/z1,z2,z3,z4
- pwm modulation ".s("pulse").z(.5).z2(3).z3(.8)"
- better delay effect with cycle relative timing ".delaytime(3/16)"
- filter envelopes for each filter type
- distort
- FX bus gain behavior is improved to work like a mixing console
- gain modules: ".gain" is pre effect ".postgain" is pre orbit effect
- ".dry" and ".wet" control the relative levels of effect bus so you can get a totally "wet" sound for example with ".room(1).dry(0)"
- relative gain of synths to samples is improved and normalized
- better sounding filters
- improved gaincurve x^2 (as opposed to x^4 in superdirt or x in Strudel )
- Juno 60 Chorus emulation ".chorus(.5)"

SuperCollider implementation of the Dirt sampler, originally designed
for the [TidalCycles](https://github.com/tidalcycles/tidal)
Expand Down Expand Up @@ -32,7 +49,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>.

## Installation from SuperCollider
```
include("SuperDirt");
in interpreter options in supercollider, include the path to this repo
```
Note: this also automatically installs the DirtSamples quark, which contains a large collection of sound files. It downloads them as a zip file. Sometimes, git fails to unpack these samples and they don't get listed. In this case, you have to unpack them "manually".

Expand Down
62 changes: 48 additions & 14 deletions classes/DirtEvent.sc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ DirtEvent {
}

play {


event.parent = orbit.defaultParentEvent;
event.use {

// s and n stand for synth/sample and note/number
~s ?? { this.splitName };

// unless orbit wide diversion returns something, we proceed
~diversion.(this) ?? {
if(~s != \) { // backslash stands for do nothing
Expand All @@ -35,15 +39,27 @@ DirtEvent {
}

splitName {

var s, n;



#s, n = ~sound.asString.split($:);
if(~bank.notNil) { s = ~bank ++ s };
~s = s.asSymbol;




~n = if(n.notNil) { n.asFloat } { 0.0 };
}

mergeSoundEvent {
var soundEvent = orbit.dirt.soundLibrary.getEvent(~s, ~n);
var soundEvent;


soundEvent = orbit.dirt.soundLibrary.getEvent(~s, ~n);

if(soundEvent.isNil) {
// only call ~notFound if no ~diversion is given that anyhow redirects control
if(~diversion.isNil) { ~notFound.value }
Expand All @@ -67,6 +83,7 @@ DirtEvent {
var accelerate = ~accelerate.value;
var avgSpeed, endSpeed;
var useUnit;
~release = ~release.value ? 0.01;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default values are usually given in the default event. Unless you need to caclulate something with ~release here, also the .value will be called automatically.


~freq = ~freq.value;
unitDuration = ~unitDuration.value;
Expand Down Expand Up @@ -102,24 +119,38 @@ DirtEvent {
};

sustain = ~sustain.value;

sustain = sustain ?? {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes below: are you sure strudel couldn't translate its logic to the way tidalcycles works? It will be very confusing to change all that …

delta = ~delta.value;
if(~legato.notNil) {
delta * ~legato.value
} {
if (useUnit and: ~clip.isNil) {
unitDuration = unitDuration ? delta;
loop !? { unitDuration = unitDuration * loop.abs };
}
} {
(delta / ~cps) * (~clip.value ? 1)
};

// if(~clip.notNil) {
// (delta / ~cps) * ~clip.value
// } {
// unitDuration = unitDuration ? delta;
// loop !? { unitDuration = unitDuration * loop.abs };
// }
};



// end samples if sustain exceeds buffer duration
// for every buffer, unitDuration is (and should be) defined.
if(useUnit) { sustain = min(unitDuration, sustain) };

~fadeTime = min(~fadeTime.value, sustain * 0.19098);
~fadeInTime = if(~begin != 0) { ~fadeTime } { 0.0 };
// if(useUnit) { sustain = min(unitDuration, sustain) };


// ~fadeTime = min(~fadeTime.value, sustain * 0.19098);
// ~fadeTime = ~fadeTime.value ? .001;
// ~fadeInTime = if(~begin != 0) { ~fadeTime } { 0.0 };
if (~timescale.notNil) {sustain = sustain * ~timescale };
~sustain = sustain - (~fadeTime + ~fadeInTime);
~totalDuration = if (useUnit) {min(unitDuration, sustain + ~release)} {sustain + ~release};
// ~sustain = sustain - (~fadeTime + ~fadeInTime);
~sustain = sustain;

~speed = speed;
~endSpeed = endSpeed;

Expand All @@ -129,6 +160,7 @@ DirtEvent {
~channel !? { ~pan = ~pan.value + (~channel.value / ~numChannels) };
~pan = ~pan * 2 - 1; // convert unipolar (0..1) range into bipolar one (-1...1)
~delayAmp = ~delay ? 0.0; // for clarity
~z1 = ~z1 ? ~n;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you explain what ~z1 is used for?

~latency = ~latency + ~lag.value + (~offset.value * ~speed.value.abs);
}

Expand All @@ -140,14 +172,15 @@ DirtEvent {
sendSynth { |instrument, args|
var group = ~synthGroup;
args = args ?? { this.getMsgFunc(instrument).valueEnvir };

args.asControlInput.flop.do { |each|
server.sendMsg(\s_new,
server.sendMsg(\s_new,
instrument,
-1, // no id
1, // add action: addToTail
group, // send to group
*each.asOSCArgArray // append all other args
)
)
}
}

Expand All @@ -160,11 +193,12 @@ DirtEvent {
*[
in: orbit.synthBus.index, // read from synth bus, which is reused
out: orbit.dryBus.index, // write to orbital dry bus
amp: ~amp,
gain: ~gain,
overgain: ~overgain,
sample: ~hash, // required for the cutgroup mechanism
cut: ~cut.abs,
release: ~release,
totalDuration: ~totalDuration,
sustain: ~sustain, // after sustain, free all synths and group
fadeInTime: ~fadeInTime, // fade in
fadeTime: ~fadeTime // fade out
Expand Down
7 changes: 4 additions & 3 deletions classes/DirtEventTypes.sc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ DirtEventTypes {
var freq, lag, sustain;
var args, midiout, hasGate, midicmd, latency, chan;
var sendNRPN, schedmidi, schedmidicmd, donecmd;
var hasNote = (~n != \none or: {~note.notNil});
// var hasNote = (~n != \none or: {~note.notNil});
var hasNote = (~n.notNil or: {~note.notNil});
var midiCommandPending = ~midicmd.notNil;
var nrpnMSB, nrpnLSB, valMSB, valLSB;
var ctlNum, control, num, val, note;
Expand Down Expand Up @@ -108,15 +109,15 @@ DirtEventTypes {

if (hasNote) {
freq = ~freq.value;
~midinote = (freq.cpsmidi).round(1).asInteger;
~midinote = ((freq.cpsmidi).round(1) ? 0).asInteger;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the default is not necessary and can be dropped. freq.cpsmidi).round(1) will never be nil.

// Assume aftertouch means no noteOn, for now..
if(~polyTouch.notNil) {
val = ~polyTouch;
note = ~midinote;
schedmidi.value({ midiout.polyTouch(chan, note, val) })
} {
// match dirt_gate SynthDef amplitude scaling
~amp = ~amp.value * pow(~gain.min(2) + ~overgain, 4);
~amp = ~amp.value * StrudelUtils.gainCurve(~gain + ~overgain, 4);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's introduce gainCurve to SuperDirt. Should it be global or orbit-wise?


sustain = ~sustain = ~sustain.value;
if(~uid.notNil and: { midiout.notNil }) {
Expand Down
20 changes: 13 additions & 7 deletions classes/DirtOrbit.sc
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@ DirtOrbit {
initDefaultGlobalEffects {
this.globalEffects = [
// all global effects sleep when the input is quiet for long enough and no parameters are set.
GlobalDirtEffect(\dirt_shimmer, [\delaytime, \delayfeedback, \delaySend, \shimmer, \cps]),
GlobalDirtEffect(\dirt_delay, [\delaytime, \delayfeedback, \delaySend, \delayAmp, \lock, \cps]),
GlobalDirtEffect(\dirt_reverb, [\size, \room, \dry]),
GlobalDirtEffect(\dirt_leslie, [\leslie, \lrate, \lsize]),
GlobalDirtEffect(\dirt_rms, [\rmsReplyRate, \rmsPeakLag]).alwaysRun_(true),
GlobalDirtEffect(\dirt_monitor, [\limitertype]).alwaysRun_(true),
GlobalDirtEffect(\dirt_monitor, [\limitertype, \outgain, \dry, \wet]).alwaysRun_(true),
]
}

Expand Down Expand Up @@ -163,6 +164,7 @@ DirtOrbit {
makeDefaultParentEvent {
defaultParentEvent = Event.make {


~cps = 1.0;
~offset = 0.0;
~begin = 0.0;
Expand All @@ -173,22 +175,26 @@ DirtOrbit {
~overgain = 0.0;
~cut = 0.0;
~unit = \r;
~n = \none; // sample number or note
~octave = 5;
~midinote = #{ ~note ? ~n + (~octave * 12) };
~n = nil;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should find a way around setting this to nil. Why can't it be \none?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically, you can just directly replace the default if you need, no need for StrudelUtils:

~dirt.set(\n, 42); // whatever you want

~octave = 0;
~midinote = #{ (~note ? ~n ? StrudelUtils.baseNote()) + (~octave * 12) };
~freq = #{ ~midinote.value.midicps };
~dur = 1.0;
~delta = #{ ~dur.value };

~latency = 0.0;
~lag = 0.0;
~length = 1.0;
~loop = 1.0;
~dry = 0.0;
~dry = 1.0;
~wet = 1.0;
~lock = 0; // if set to 1, syncs delay times with cps

~amp = 0.4;
~amp = 1;
~fadeTime = 0.001;
~delaytime = 0.1875;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% sure, but I think this means that there is always delay on. This can be set for each piece separately.

~delayfeedback = 0.15;
~lock = 1;
~outgain = 1; // output gain that drives the final limiter


// values from the dirt bus
Expand Down
39 changes: 34 additions & 5 deletions classes/DirtSoundLibrary.sc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ DirtSoundLibrary {
synthEvents.clear;
this.freeAllSoundFiles;
}
// extractParts { |str|
// // Regex to split the string into numeric and non-numeric parts
// str.collect { |part|
// part.isNumber ifTrue: { part.asInteger } ifFalse: { part }
// };
// }

// sortStringsAlphanumerically { |stringArray|
// stringArray.sort { |a, b|
// var partsA = this.extractParts.(a);
// var partsB = this.extractParts.(b);

// partsA.zip(partsB).detect { |pair|
// var (partA, partB) = pair;
// partA < partB ifTrue: { ^-1 };
// partA > partB ifTrue: { ^1 };
// };

// 0 // They are equal
// };
// }

addBuffer { |name, buffer, appendToExisting = false, metaData|
var event, index;
Expand All @@ -51,6 +72,7 @@ DirtSoundLibrary {
}

addSynth { |name, event, appendToExisting = false, useSynthDefSustain = false, metaData|

if(bufferEvents[name].notNil) {
"a sample buffer with that name already exists: %\nSkipping...".format(name).warn;
^this
Expand Down Expand Up @@ -107,6 +129,8 @@ DirtSoundLibrary {

set { |name, indices ... pairs|
var allEvents = this.at(name);


if(allEvents.isNil) {
"set: no events found with this name: %\n".format(name).warn
} {
Expand Down Expand Up @@ -179,7 +203,9 @@ DirtSoundLibrary {
};

files = pathMatch(folderPath.standardizePath +/+ "*"); // dependent on operating system
if(sortFiles) { files.sort };
if(sortFiles) {
files.sort;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in sclang, there is no ; inside the last statement of a function. It is not wrong, but the change is not needed.

};

if(files.notEmpty) {
name = name.asSymbol;
Expand All @@ -195,7 +221,9 @@ DirtSoundLibrary {

filePaths.do { |filepath|
try {

var buf, metaData;

buf = this.readSoundFile(filepath);
if(buf.notNil) {
metaData = this.readMetaData(filepath);
Expand Down Expand Up @@ -283,6 +311,7 @@ DirtSoundLibrary {

var allEvents = this.at(name);
var event;


if(allEvents.isNil) {
// first look up buffers, then synths
Expand All @@ -298,8 +327,7 @@ DirtSoundLibrary {
^event

} {
// the index may be \none (a Symbol), but this converts it to 0
event = allEvents.wrapAt(index.asInteger);
event = allEvents.wrapAt((index ? 0).asInteger);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be revisited in SuperDirt.

};

if(doNotReadYet and: { event.notNil and: { event[\notYetRead] ? false } }) {
Expand All @@ -320,8 +348,9 @@ DirtSoundLibrary {
}

makeEventForBuffer { |buffer, metaData|
var baseFreq = 60.midicps;
var baseFreq = StrudelUtils.baseNote().midicps;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally kept separate DirtSoundLibrary and SuperDirt. This StrudelUtils.baseNote(). couples both to one system. MAybe we find a way around this?

var baseFreqToMetaFreqRatio = metaData !? _[\baseFreqToMetaFreqRatio] ? 1.0;

^(
buffer: buffer.bufnum,
bufferObject: buffer,
Expand All @@ -340,7 +369,7 @@ DirtSoundLibrary {
},
unitDuration: { buffer.duration * baseFreq / (~freq.value * ~metaDataTuneRatio.value) },
hash: buffer.identityHash,
note: 0
note: StrudelUtils.baseNote()
)
}

Expand Down
1 change: 0 additions & 1 deletion classes/GlobalDirtEffect.sc
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ GlobalDirtEffect {
)
}


release { |releaseTime = 0.2|
if(synth.notNil) {
synth.server.sendBundle(nil,
Expand Down
Loading