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

Add new Autotuner fx #3088

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions BUILD-LINUX.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ few dependencies:
* Ruby + Dev tools (2.5+)
* Elixir + Dev tools (12.0+)
* SuperCollider + SC3 plugins
* (Optional) Additional SuperCollider plugins

Note: please make sure that you have gcc12 installed. Compiling vcpkg dependencies does not work with gcc13 currently

Expand Down Expand Up @@ -86,6 +87,18 @@ sudo dnf install alsa-utils aubio-devel catch-devel cmake crossguid-devel elixir

There is an Audinux Copr [repository]()https://copr.fedorainfracloud.org/coprs/ycollet/audinux/package/sonic-pi/) with Sonic-Pi.

### 1.3 (Optional) Additional SuperCollider Plugins

Some audio effects and synthesizer are not distributed with the `sc3-plugins-server` package and prebuilt binaries are not provided with the Sonic Pi repo. To use these with your version of Sonic Pi, you can find build instructions at the following repositories:

* https://github.com/xavriley/qlibugens/ - used by the `:autotuner_two` effect.
* (more to follow as we implement other plugins)

After building the plugins, make sure you copy them to your [SuperCollider Extensions folder](https://doc.sccode.org/Guides/UsingExtensions.html) before starting Sonic Pi.

If you don't do this, everything else will still work as normal - you just won't be able to use these particular effects.


## 2. Preparing the Build

Once we have installed all the dependencies, we're almost ready to build
Expand Down
144 changes: 144 additions & 0 deletions app/server/ruby/lib/sonicpi/synths/synthinfo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5652,6 +5652,149 @@ def specific_arg_info
end
end

class FXAutotuner2 < FXInfo
def name
"Autotuner2"
end

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

def synth_name
"fx_autotuner_two"
end

def doc
"Another autotune effect. Used without any arguments, it tries to detect the pitch and shift it to the nearest exact note. This can help with out of tune singing, but it's also an interesting effect in its own right. When used with the note: arg, it tries to shift the input to match that note instead. This gives that classic \"robot singing\" sound that people associate with vocoders. This can then be changed using the control method to create new melodies.

```
with_fx :autotuner_two do |c|
```

```
sample \"~/Downloads/acappella.wav\" # any sample with a voice is good
```

```
sleep 4
```

```
# listen to standard auto-tune behaviour for 4 seconds
```

```
64.times do
```

```
# now start changing note: to get robot voice behaviour
```

```
control c, note: (scale :a2, :minor_pentatonic, num_octaves: 2).choose
```

```
sleep 0.5
```

```
end
```

```
end
```
"
end

def arg_defaults
super.merge({
:note => -1,
:note_slide => 0,
:note_slide_shape => 1,
:note_slide_curve => 0,
:transpose => 0,
:key => 0,
:scale => 0
})
end

def munge_opts(studio, args_h)
keys = {
nil => nil,
:c => 0,
:cs => 1,
:db => 1,
:d => 2,
:ds => 3,
:eb => 3,
:e => 4,
:f => 5,
:fs => 6,
:gb => 6,
:g => 7,
:gs => 8,
:ab => 8,
:a => 9,
:as => 10,
:bb => 10,
:b => 11
}
args_h[:key] = keys[args_h[:key]]

scales = {
nil => nil,
:none => 0,
:chromatic => 0,
:major => 1,
:major_pentatonic => 2,
:minor_pentatonic => 3
}

args_h[:scale] = scales[args_h[:scale]]

puts args_h
args_h
end

def specific_arg_info
{
:note =>
{
:doc => "Midi note to shift pitch to. The quality of the sound depends on how stable the pitch of the input is. If set, this will override the scale and key options. Set to -1 to turn this off.",
:validations => [v_between_inclusive(:note, -2, 127)],
:modulatable => true
},

:key =>
{
:doc => "Key to lock the output pitches to. One of :c, :cs, :d, :e, :f, :fs, :g, :gs, :a, :as, or :b.",
:validations => [v_one_of(:key, [nil, :c, :cs, :db, :d, :ds, :eb, :e, :f, :fs, :gb, :g, :gs, :ab, :a, :as, :bb, :b,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])],
:modulatable => false
},

:scale =>
{
:doc => "Scale to lock the output pitches to. One of :none, :chromatic, :major, :major_pentatonic or :minor_pentatonic.",
:validations => [v_one_of(:scale, [nil, :none, :chromatic, :major, :major_pentatonic, :minor_pentatonic,
0, 1, 2, 3])],
:modulatable => false
},

:transpose =>
{
:doc => "Number of semitones to shift the output up or down, with a maximum of +24 (two octaves up) and a minimum of -24 (two octaves down).",
:validations => [v_between_inclusive(:transpose, -24, 24)],
:modulatable => true
}
}
end
end

class FXMono < FXInfo
def name
"Mono"
Expand Down Expand Up @@ -8453,6 +8596,7 @@ class BaseInfo
:fx_level => FXLevel.new,
:fx_mono => FXMono.new,
:fx_autotuner => FXAutotuner.new,
:fx_autotuner_two => FXAutotuner2.new,
:fx_replace_level => FXLevel.new,
:fx_echo => FXEcho.new,
:fx_replace_echo => FXEcho.new,
Expand Down
Binary file not shown.
92 changes: 92 additions & 0 deletions etc/synthdefs/designs/supercollider/autotuner_two.sc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Autotune style plugin based on the orignal Antares patent (US Patent US5973252 - now expired). Uses Cycfi's Bitstream Autocorrelation (BACF) for pitch tracking.
// See https://github.com/xavriley/qlibugens for details of the SC UGens

(
SynthDef('sonic-pi-fx_autotuner_two', {|
//standard args
pre_amp=1,
pre_amp_slide=0,
pre_amp_slide_shape=1,
pre_amp_slide_curve=0,
amp=1,
amp_slide=0,
amp_slide_shape=1,
amp_slide_curve=0,
mix=1,
mix_slide=0,
mix_slide_shape=1,
mix_slide_curve=0,
pre_mix=1,
pre_mix_slide=0,
pre_mix_slide_shape=1,
pre_mix_slide_curve=0
out_bus=0,
in_bus=0,
// args specific to this synth
note = -1,
note_slide=0,
note_slide_shape=1,
note_slide_curve=0,
min_freq = 50,
transpose=0,
key=0,
scale=0|

var pitch_ratio,
in,
snd,
freq,
// args for Sonic Pi plumbing
fxArgMix,
fxArgPreMix,
fxArgAmp,
fxArgPreAmp,
inLeft,
inRight,
fxArgInvPreMix,
fxArgBypassL,
fxArgBypassR,
dryL,
dryR,
wetL,
wetR,
finL,
finR;

// plumbing for Sonic Pi standard args
fxArgMix = VarLag.kr(mix.clip(0,1), mix_slide, mix_slide_curve, mix_slide_shape);
fxArgMix = LinLin.kr(fxArgMix, 0, 1, -1, 1);

fxArgPreMix = VarLag.kr(pre_mix.clip(0,1), pre_mix_slide, pre_mix_slide_curve, pre_mix_slide_shape);

fxArgAmp = VarLag.kr(amp, amp_slide, amp_slide_curve, amp_slide_shape);
fxArgPreAmp = VarLag.kr(pre_amp, pre_amp_slide, pre_amp_slide_curve, pre_amp_slide_shape);

# inLeft, inRight = In.ar(in_bus, 2) * fxArgPreAmp;
fxArgInvPreMix = 1 - fxArgPreMix;

fxArgBypassL = fxArgInvPreMix * inLeft;
fxArgBypassR = fxArgInvPreMix * inRight;

dryL = fxArgPreMix * inLeft;
dryR = fxArgPreMix * inRight;

// note represents a midi "target" pitch to tune to
// without that arg, it works as a normal autotune, locking the
// input to the nearest midi note
note = note.varlag(note_slide, note_slide_curve, note_slide_shape);

wetL = BitstreamPitchCorrection.ar(inLeft, min_freq, transpose: transpose, key: key, scale: scale, target_note: note);
wetR = wetL;

// plumbing for Sonic Pi output
wetL = wetL + fxArgBypassL;
wetR = wetR + fxArgBypassR;

finL = XFade2.ar(inLeft, wetL, fxArgMix, fxArgAmp);
finR = XFade2.ar(inRight, wetR, fxArgMix, fxArgAmp);

Out.ar(out_bus, [finL, finR]);
}
).writeDefFile("/Users/sam/Development/RPi/sonic-pi/etc/synthdefs/compiled/")
)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.