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
211 changes: 211 additions & 0 deletions app/server/ruby/lib/sonicpi/synths/synthinfo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3290,6 +3290,214 @@ def arg_defaults
end
end

class WinwoodLead < SonicPiSynth
def name
"Winwood Lead"
end

def introduced
Version.new(3,3,0)
end

def synth_name
"winwood_lead"
end

def on_start(studio, args_h)
args_h[:rand_buf] = studio.rand_buf_id
end

def doc
"A lead synth inspired by the Winwood songs from the early 80s. Adapted for Sonic Pi from [Steal This Sound](https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd). Published there under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html), so re-published under the same terms. The source code is available [on the Sonic Pi GitHub repository](https://github.com/sonic-pi-net/sonic-pi). Date of modification: 10.01.2021"
Copy link
Collaborator

@ethancrawford ethancrawford Jan 13, 2021

Choose a reason for hiding this comment

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

If I were to be really picky, is an average user going to need to know directly from the GUI's synth docs exactly what license it is and how or where to find the source code? We could leave notes like that in the sclang file maybe 🤷‍♂️ (perhaps it doesn't really matter if we leave it in, but I thought this was a reasonable question to ask 😅 🤷‍♂️)

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 was wondering about that, too, but I have tried to comply with GPL v3, and that license explicitly requires that:

"5 d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so."

Copy link
Collaborator

Choose a reason for hiding this comment

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

@samaaron - shall we leave the license and source code link in the synth doc here given the above?

Copy link
Collaborator

Choose a reason for hiding this comment

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

We already have an explicit user interface component that shows that the app is distributed under a GPL license which is built into the GUI under a section called "License". I'm assuming that this is sufficient and we don't have to explicitly document it in the built-in documentation - although I do like having a link to the original designs so people can see the provenance.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@level-xx would you be ok removing all the license stuff from the docs, keeping a URL to the original project and then adding an entry to the License.md file covering these synths?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, that's the best way. I was unaware of the license component. Just to avoid creating a mess ... I have noticed you have changed the base branch from main to dev. So, I would pull, merge my previous changes into dev, make the new license changes, and push to dev, correct?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@level-xx @samaaron I suggest using GPL for the synthdefs and MIT for the synth metadata and documentation as Sam suggested in his recent comment on this PR. Regarding the target of this PR - you can just make a new PR with all the adjusted code ready to go, and targeted at dev 🙂

end

def arg_defaults
{
:note => 69,
:note_slide => 0,
:note_slide_shape => 1,
:note_slide_curve => 0,
:amp => 1,
:amp_slide => 0,
:amp_slide_shape => 1,
:amp_slide_curve => 0,
:pan => 0,
:pan_slide => 0,
:pan_slide_shape => 1,
:pan_slide_curve => 0,

:attack => 0.01,
:decay => 0,
:sustain => 0.9,
:release => 0.05,
:attack_level => 1,
:decay_level => 0.5,
:sustain_level => 0.5,

:cutoff => 119,
:cutoff_slide => 0,
:cutoff_slide_shape => 1,
:cutoff_slide_curve => 0,

:res => 0.8,
:res_slide => 0,
:res_slide_shape => 1,
:res_slide_curve => 0,
:lfo_width => 0.01,
:lfo_width_slide => 0,
:lfo_width_slide_shape => 1,
:lfo_width_slide_curve => 0,
:lfo_rate => 8,
:lfo_rate_slide => 0,
:lfo_rate_slide_shape => 1,
:lfo_rate_slide_curve => 0,
:seed => 0,
}
end

def specific_arg_info
{
:seed =>
{
:doc => "Seed value for rand num generator used for the phase offset of the triangle low-frequency oscillator (LFO)",
:modulatable => false
},
:lfo_width =>
{
:doc => "Width of the low-frequency oscillator (LFO) which determines how wide base tones oscillate around their base frequencies",
:modulatable => true
Copy link
Collaborator

Choose a reason for hiding this comment

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

Does lfo_width: need validations? (same with other non-default opts in these synths)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, yes, thanks, both lfo_rateand lfo_width should be non-negative:

:validations => [v_positive(:lfo_rate)],

and

:validations => [v_positive(:lfo_width)],

in their corresponding sections.

Copy link
Collaborator

@ethancrawford ethancrawford Jan 18, 2021

Choose a reason for hiding this comment

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

Agreed for :lfo_width, but I think maybe :lfo_rate should be greater than zero?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just checked that in SuperCollider: :lfo_rate is fed into an LFTrioscillator as the frequency argument. Zero is OK and doesn't break it. It gives a flat line, of course. For practical reasons, I'd allow zero. This way, for example, the user can slide down the rate to zero without causing a validation error.

},
:lfo_rate =>
{
:doc => "Width of the low-frequency oscillator (LFO) which determines how fast base tones oscillate around their base frequencies",
Copy link
Collaborator

Choose a reason for hiding this comment

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

This docstring was presumably meant to be updated?
Also, just to keep in mind for the new docstring, most of the time when we've talked about opts that are measured in units of time, we've done so in beats. (I say most because I think there are a few exceptions here and there).
@samaaron - do we want to talk about rate in an lfo_rate docstring in terms of beats per second rather than Hz?
Perhaps something like:

Suggested change
:doc => "Width of the low-frequency oscillator (LFO) which determines how fast base tones oscillate around their base frequencies",
:doc => "Rate in beats per second that the low-frequency oscillator (LFO) oscillates between its low and high values",

?

Copy link
Contributor Author

@level-xx level-xx Jan 14, 2021

Choose a reason for hiding this comment

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

Oops, sure, that was supposed to be "rate", of course. As to the unit: The synthdef code actually uses Hz. I won't be very passionate about it, but the idea was that Hz would be the right thing here. As far as I can see we have no configurable LFO in other synths and fx yet, so there is no precedence. SP synths and fx deal with 2 types of frequencies up to now: the note and the beat. I suppose, neither of them really fits. If you consider we should go with either note or beats, then I think beats will infact be the better choice.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@samaaron - would value your input on this one when you are able.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think this depends on whether this rate is more closely tied to the sound made by the synth, or the rhythm of the surrounding piece. I.e. if you were to change the tempo of the music without changing the notes, would you expect this rate to increase with the tempo, or to stay constant?

Copy link
Collaborator

Choose a reason for hiding this comment

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

@samaaron - would value your input on this one when you are able.

As mentioned before in this thread, this all looks great but I'm currently 100% focussed on getting the new release out. I'm happy to get back into this conversation then :-)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@emlyn: I'd say it should stay constant. The effect of the LFO is similar to those in a vibraphone or a hammond organ.

:modulatable => true
},
}
end
end

class BassFoundation < SonicPiSynth
def name
"Bass Foundation"
end

def introduced
Version.new(3,3,0)
end

def synth_name
"bass_foundation"
end

def doc
"A soft bass synth inspired by the sounds of the 80s. Use together with :bass_highend if you want to give it a gargling component. Adapted for Sonic Pi from [Steal This Sound](https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd). Published there under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html), so re-published under the same terms. The source code is available [on the Sonic Pi GitHub repository](https://github.com/sonic-pi-net/sonic-pi). Date of modification: 10.01.2021"
end

def arg_defaults
{
:note => 40,
:note_slide => 0,
:note_slide_shape => 1,
:note_slide_curve => 0,
:amp => 1,
:amp_slide => 0,
:amp_slide_shape => 1,
:amp_slide_curve => 0,
:pan => 0,
:pan_slide => 0,
:pan_slide_shape => 1,
:pan_slide_curve => 0,

:attack => 0.01,
:decay => 0,
:sustain => 0.9,
:release => 0.05,
:attack_level => 1,
:decay_level => 0.5,
:sustain_level => 0,

:cutoff => 83,
:cutoff_slide => 0,
:cutoff_slide_shape => 1,
:cutoff_slide_curve => 0,

:res => 0.5,
:res_slide => 0,
:res_slide_shape => 1,
:res_slide_curve => 0,
}
end
end

class BassHighend < SonicPiSynth
def name
"Bass Highend"
end

def introduced
Version.new(3,3,0)
end

def synth_name
"bass_highend"
end

def doc
"An addition to the :bass_foundation synth inspired by the sounds of the 80s. Use them together if you want to give it a rough, slurping, or gargling component. Adapted for Sonic Pi from [Steal This Sound](https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd). Published there under [GPL v3](https://www.gnu.org/licenses/gpl-3.0.en.html), so re-published under the same terms. The source code is available [on the Sonic Pi GitHub repository](https://github.com/sonic-pi-net/sonic-pi). Date of modification: 11.01.2021"
end

def arg_defaults
{
:note => 40,
:note_slide => 0,
:note_slide_shape => 1,
:note_slide_curve => 0,
:amp => 1,
:amp_slide => 0,
:amp_slide_shape => 1,
:amp_slide_curve => 0,
:pan => 0,
:pan_slide => 0,
:pan_slide_shape => 1,
:pan_slide_curve => 0,

:attack => 0.01,
:decay => 0,
:sustain => 0.9,
:release => 0.05,
:attack_level => 1,
:decay_level => 0.5,
:sustain_level => 0,

:cutoff => 102,
:cutoff_slide => 0,
:cutoff_slide_shape => 1,
:cutoff_slide_curve => 0,

:res => 0.1,
:res_slide => 0,
:res_slide_shape => 1,
:res_slide_curve => 0,

:drive => 2.0,
:drive_slide => 0,
:drive_slide_shape => 1,
:drive_slide_curve => 0,
}
end

def specific_arg_info
{
:drive =>
{
:doc => "Higher drive values make the sound louder and rougher.",
:validations => [v_positive(:drive)],
:modulatable => true
},
}
end
end

class StudioInfo < SonicPiSynth
def user_facing?
false
Expand Down Expand Up @@ -7949,6 +8157,9 @@ class BaseInfo
:kalimba => SynthKalimba.new,
:pluck => SynthPluck.new,
:tech_saws => TechSaws.new,
:winwood_lead => WinwoodLead.new,
:bass_foundation => BassFoundation.new,
:bass_highend => BassHighend.new,

:sound_in => SoundIn.new,
:sound_in_stereo => SoundInStereo.new,
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
46 changes: 46 additions & 0 deletions etc/synthdefs/designs/supercollider/bass_foundation.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Adapted for Sonic Pi from
// https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd
// Published there under GPL v3, so re-published under the same terms, see:
// https://www.gnu.org/licenses/gpl-3.0.en.html
// Date of modification: 10.01.2021

(
SynthDef('sonic-pi-bass_foundation', {|
note = 40, note_slide = 0, note_slide_shape = 1, note_slide_curve = 0,
amp = 1, amp_slide = 0, amp_slide_shape = 1, amp_slide_curve = 0,
pan = 0, pan_slide = 0, pan_slide_shape = 1, pan_slide_curve = 0,
attack = 0.01, decay = 0, sustain = 0.9, release = 0.05,
attack_level = 1, decay_level = 0.5, sustain_level = 0,
cutoff = 83, cutoff_slide = 0, cutoff_slide_shape = 1, cutoff_slide_curve = 0,
res = 0.5, res_slide = 0, res_slide_shape = 1, res_slide_curve = 0,
out_bus = 0|

var snd, osc, env, filterenv;

note = note.midicps;
note = note.varlag(note_slide, note_slide_curve, note_slide_shape);
decay_level = Select.kr(decay_level < 0, [decay_level, sustain_level]);
amp = amp.varlag(amp_slide, amp_slide_curve, amp_slide_shape);
pan = pan.varlag(pan_slide, pan_slide_curve, pan_slide_shape);

cutoff = cutoff.midicps;
cutoff = cutoff.varlag(cutoff_slide, cutoff_slide_curve, cutoff_slide_shape);

res = res.varlag(res_slide, res_slide_curve, res_slide_shape);

osc = Saw.ar(note);

filterenv = EnvGen.ar(Env.adsr(0.0, 0.5, 0.2, 0.2), 1, doneAction:2);
snd = RLPF.ar(osc,cutoff*filterenv+100, res);

env = Env.new(
[0, attack_level, decay_level, sustain_level, 0],
[attack,decay,sustain,release],
\lin
);

snd = Pan2.ar(Mix(snd) * EnvGen.kr(env, doneAction: 2), pan);

Out.ar(out_bus, snd * amp);
}).writeDefFile("/Users/sam/Development/RPi/sonic-pi/etc/synthdefs/compiled/");
)
58 changes: 58 additions & 0 deletions etc/synthdefs/designs/supercollider/bass_highend.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Adapted for Sonic Pi from
// https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd
// Published there under GPL v3, so re-published under the same terms, see:
// https://www.gnu.org/licenses/gpl-3.0.en.html
// Date of modification: 11.01.2021

(
SynthDef('sonic-pi-bass_highend',{|
note = 40, note_slide = 0, note_slide_shape = 1, note_slide_curve = 0,
amp = 1, amp_slide = 0, amp_slide_shape = 1, amp_slide_curve = 0,
pan = 0, pan_slide = 0, pan_slide_shape = 1, pan_slide_curve = 0,
attack = 0.01, decay = 0, sustain = 0.9, release = 0.05,
attack_level = 1, decay_level = 0.5, sustain_level = 0,
cutoff = 102, cutoff_slide = 0, cutoff_slide_shape = 1, cutoff_slide_curve = 0,
res = 0.1, res_slide = 0, res_slide_shape = 1, res_slide_curve = 0,
drive = 2.0, drive_slide = 0, drive_slide_shape = 1, drive_slide_curve = 0,
out_bus = 0|

var osc, snd, env, filterenv, ab;

note = note.midicps;
note = note.varlag(note_slide, note_slide_curve, note_slide_shape);
decay_level = Select.kr(decay_level < 0, [decay_level, sustain_level]);
amp = amp.varlag(amp_slide, amp_slide_curve, amp_slide_shape);
pan = pan.varlag(pan_slide, pan_slide_curve, pan_slide_shape);

cutoff = cutoff.midicps;
cutoff = cutoff.varlag(cutoff_slide, cutoff_slide_curve, cutoff_slide_shape);

res = res.varlag(res_slide, res_slide_curve, res_slide_shape);

drive = drive.varlag(drive_slide, drive_slide_curve, drive_slide_shape);

osc = Mix(Saw.ar(note*[0.25,1,1.5],[0.5,0.4,0.1]));
filterenv = EnvGen.ar(Env.adsr(0.0,0.5,0.2,0.2), doneAction:2);
snd = RLPF.ar(osc,cutoff*filterenv+100,res);

ab = abs(snd);
snd = (snd*(ab + drive)/(snd ** 2 + (drive - 1) * ab + 1));

// Remove low end
snd = BLowShelf.ar(snd, 300, 1.0, -12);

// Dip at 1600Hz
snd = BPeakEQ.ar(snd, 1600, 1.0, -6);

env = Env.new(
[0, attack_level, decay_level, sustain_level, 0],
[attack,decay,sustain,release],
\lin
);

snd = Pan2.ar(Mix(snd) * EnvGen.kr(env, doneAction: 2) * 2, pan);

Out.ar(out_bus, snd * amp);

}).writeDefFile("/Users/sam/Development/RPi/sonic-pi/etc/synthdefs/compiled/");
)
58 changes: 58 additions & 0 deletions etc/synthdefs/designs/supercollider/winwood_lead.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Adapted for Sonic Pi from
// https://raw.githubusercontent.com/supercollider/supercollider/develop/examples/demonstrations/stealthissound.scd
// Published there under GPL v3, so re-published under the same terms, see:
// https://www.gnu.org/licenses/gpl-3.0.en.html
// Date of modification: 10.01.2021

(
SynthDef('sonic-pi-winwood_lead', {|
note = 69, note_slide = 0, note_slide_shape = 1, note_slide_curve = 0,
amp = 1, amp_slide = 0, amp_slide_shape = 1, amp_slide_curve = 0,
pan = 0, pan_slide = 0, pan_slide_shape = 1, pan_slide_curve = 0,
attack = 0.01, decay = 0, sustain = 0.9, release = 0.05,
attack_level = 1, decay_level = 0.5, sustain_level = 0.5,
cutoff = 119, cutoff_slide = 0, cutoff_slide_shape = 1, cutoff_slide_curve = 0,
lfo_width = 0.01, lfo_width_slide = 0, lfo_width_slide_shape = 1, lfo_width_slide_curve = 0,
lfo_rate = 8, lfo_rate_slide = 0, lfo_rate_slide_shape = 1, lfo_rate_slide_curve = 0,
res = 0.8, res_slide = 0, res_slide_shape = 1, res_slide_curve = 0,
seed = 0, rand_buf = 0,
out_bus = 0|

var snd, pulse, env, lfo;
var rand_val;

note = note.midicps;
note = note.varlag(note_slide, note_slide_curve, note_slide_shape);
decay_level = Select.kr(decay_level < 0, [decay_level, sustain_level]);
amp = amp.varlag(amp_slide, amp_slide_curve, amp_slide_shape);
pan = pan.varlag(pan_slide, pan_slide_curve, pan_slide_shape);

cutoff = cutoff.midicps;
cutoff = cutoff.varlag(cutoff_slide, cutoff_slide_curve, cutoff_slide_shape);

lfo_width = lfo_width.varlag(lfo_width_slide, lfo_width_slide_curve, lfo_width_slide_shape);
lfo_rate = lfo_rate.varlag(lfo_rate_slide, lfo_rate_slide_curve, lfo_rate_slide_shape);

res = res.varlag(res_slide, res_slide_curve, res_slide_shape);

rand_val = BufRd.kr(1, rand_buf, seed, 1);

lfo = LFTri.kr(lfo_rate,(rand_val*2.0)!2);

pulse = Mix(Pulse.ar(note*[1,1.001]*(1.0+(lfo_width*lfo)),[0.2,0.19]))*0.5;

snd = RLPF.ar(pulse,cutoff,res);

snd = BLowShelf.ar(snd,351,1.0,-9);

env = Env.new(
[0, attack_level, decay_level, sustain_level, 0],
[attack,decay,sustain,release],
\lin
);

snd = Pan2.ar(Mix(snd) * EnvGen.kr(env, doneAction: 2), pan);

Out.ar(out_bus, snd * amp);
}).writeDefFile("/Users/sam/Development/RPi/sonic-pi/etc/synthdefs/compiled/");
)