Skip to content

Commit eaebc06

Browse files
committed
add LFDNoise, Rand, Klank, DetectSilence. add Max and SoftClip methods to Input interface
1 parent 6233594 commit eaebc06

18 files changed

+294
-25
lines changed

Makefile

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
PLATFORM = $(shell uname -s)
33

44
ifeq ($(PLATFORM),Darwin)
5-
SCLANG = /Applications/SuperCollider/SuperCollider.app/Contents//Resources/sclang
5+
SCLANG = /Applications/SuperCollider.app/Contents/MacOS/sclang
66
endif
77

88
ifeq ($(PLATFORM),Linux)
@@ -74,6 +74,8 @@ FIXTURES = fixtures/AllpassExample.scsyndef \
7474
all:
7575
@go install
7676

77+
fixtures: $(FIXTURES)
78+
7779
$(FIXTURES): fixtures/synthdefs.sc
7880
@cd fixtures $(SCLANG) synthdefs.sc
7981

@@ -85,9 +87,9 @@ coverage:
8587
@go test -coverprofile cover.out && go tool cover -html cover.out -o cover.html
8688

8789
clean:
88-
@rm -rf *~ *.gosyndef *.svg *.dot *.json *.xml
90+
@rm -rf *~ *.gosyndef *.svg *.dot *.json *.xml fixtures/*.scsyndef
8991

9092
test: $(FIXTURES)
9193
@go test
9294

93-
.PHONY: all clean test
95+
.PHONY: all clean fixtures test

binop.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package sc
22

3+
// BinOpMax creates a BinaryOpUgen that represents the maximum of two signals.
4+
func BinOpMax(rate int8, x, y Input, numOutputs int) *UgenNode {
5+
CheckRate(rate)
6+
return NewUgenNode("BinaryOpUGen", rate, 13, numOutputs, x, y)
7+
}
8+
39
// BinOpMul creates a BinaryOpUGen that represents multiplication.
410
func BinOpMul(rate int8, x, y Input, numOutputs int) *UgenNode {
511
CheckRate(rate)
@@ -16,3 +22,9 @@ func BinOpAdd(rate int8, x, y Input, numOutputs int) *UgenNode {
1622
func MulAdd(rate int8, in, mul, add Input, numOutputs int) *UgenNode {
1723
return NewUgenNode("MulAdd", rate, 0, numOutputs, in, mul, add)
1824
}
25+
26+
// BinOpSoftClip adds distortion to a ugen.
27+
func BinOpSoftClip(rate int8, in Input, numOutputs int) *UgenNode {
28+
CheckRate(rate)
29+
return NewUgenNode("BinaryOpUGen", rate, 43, numOutputs, in)
30+
}

c.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ package sc
33
// C wraps a float32 and implements the Input interface.
44
type C float32
55

6+
func (c C) Max(other Input) Input {
7+
if v, ok := other.(C); ok {
8+
return C(maxFloat32(float32(c), float32(v)))
9+
}
10+
return other.Max(c)
11+
}
12+
613
// Mul multiplies the constant by another input.
714
func (c C) Mul(val Input) Input {
815
if v, ok := val.(C); ok {
@@ -29,3 +36,20 @@ func (c C) MulAdd(mul, add Input) Input {
2936
}
3037
return mul.MulAdd(c, add)
3138
}
39+
40+
// SoftClip clips the constant to the range [-0.5, 0.5]
41+
func (c C) SoftClip() Input {
42+
if float32(c) < -0.5 {
43+
return C(-0.5)
44+
} else if float32(c) > 0.5 {
45+
return C(0.5)
46+
}
47+
return c
48+
}
49+
50+
func maxFloat32(f1, f2 float32) float32 {
51+
if f1 > f2 {
52+
return f1
53+
}
54+
return f2
55+
}

control.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ func (ctl *Control) Add(val Input) Input {
3737
return ctl
3838
}
3939

40+
// Max computes the maximum of the Control and another UGen.
41+
func (ctl *Control) Max(other Input) Input {
42+
return ctl
43+
}
44+
4045
// Mul multiplies another input by the Control.
4146
func (ctl *Control) Mul(val Input) Input {
4247
return ctl
@@ -47,6 +52,11 @@ func (ctl *Control) MulAdd(mul, add Input) Input {
4752
return ctl
4853
}
4954

55+
// SoftClip adds distortion to the Control.
56+
func (ctl *Control) SoftClip() Input {
57+
return ctl
58+
}
59+
5060
// NewControl creates a new Control.
5161
func NewControl(numOutputs int) Ugen {
5262
outputs := make([]Output, numOutputs)

detect_silence.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package sc
2+
3+
// DetectSilence evaluates Done when input falls below a certain threshold.
4+
type DetectSilence struct {
5+
In Input // The input signal.
6+
Amp Input // Amplitude threshold.
7+
Time Input // The minimum duration for which amplitude must be below Amp before Done triggers.
8+
Done int // UGen done-action.
9+
}
10+
11+
func (ds *DetectSilence) defaults() {
12+
if ds.Amp == nil {
13+
ds.Amp = C(0.0001)
14+
}
15+
if ds.Time == nil {
16+
ds.Time = C(0.1)
17+
}
18+
}
19+
20+
// Rate creates a new ugen at a specific rate.
21+
// If rate is an unsupported value this method will cause a runtime panic.
22+
func (ds DetectSilence) Rate(rate int8) Input {
23+
if ds.In == nil {
24+
panic("DetectSilence expects In to not be nil")
25+
}
26+
CheckRate(rate)
27+
(&ds).defaults()
28+
return UgenInput("DetectSilence", rate, 0, 1, ds.In, ds.Amp, ds.Time)
29+
}

detectsilence_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package sc
2+
3+
import "testing"
4+
5+
func TestDetectSilence(t *testing.T) {
6+
const name = "DetectTheSilence"
7+
8+
def := NewSynthdef(name, func(params Params) Ugen {
9+
out := params.Add("out", 0)
10+
11+
sine := SinOsc{
12+
Freq: Rand{
13+
Lo: C(400),
14+
Hi: C(700),
15+
},
16+
}.Rate(AR)
17+
return Out{
18+
Bus: out,
19+
Channels: sine.Mul(LFDNoise{
20+
Interpolation: InterpolationCubic,
21+
Freq: C(8),
22+
}.Rate(KR)),
23+
}.Rate(AR)
24+
})
25+
same, err := def.CompareToFile("fixtures/DetectSilence.scsyndef")
26+
if err != nil {
27+
t.Fatal(err)
28+
}
29+
if !same {
30+
t.Fatalf("synthdef different from sclang version")
31+
}
32+
}

fixtures/DetectSilence.scsyndef

448 Bytes
Binary file not shown.

fixtures/THX.scsyndef

0 Bytes
Binary file not shown.

fixtures/THX1.scsyndef

-1.15 KB
Binary file not shown.

fixtures/synthdefs.sc

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -327,23 +327,28 @@ SynthDef(\MixTest, {
327327
}).writeDefFile(File.getcwd);
328328

329329
SynthDef(\THX, {
330-
var numVoices = 30;
331-
var fundamentals = ({rrand(200.0, 400.0)}!numVoices).sort;
332-
var finalPitches = (numVoices.collect({|nv| (nv/(numVoices/6)).round * 12; }) + 14.5).midicps;
333-
var sweepEnv = EnvGen.kr(Env([0, 0.1, 1], [5, 8], [2, 5]));
334-
var sig = Mix
335-
({|numTone|
330+
var numVoices = 30;
331+
var fundamentals = ({rrand(200.0, 400.0)}!numVoices).sort;
332+
var finalPitches = (numVoices.collect({|nv| (nv/(numVoices/6)).round * 12; }) + 14.5).midicps;
333+
var sweepEnv = EnvGen.kr(Env([0, 0.1, 1], [5, 8], [2, 5]));
334+
var sig = Mix({ |numTone|
336335
var initRandomFreq = fundamentals[numTone] + LFNoise2.kr(0.5, 3 * (numTone + 1));
337336
var destinationFreq = finalPitches[numTone] + LFNoise2.kr(0.1, (numTone / 4));
338337
var freq = ((1 - sweepEnv) * initRandomFreq) + (sweepEnv * destinationFreq);
339-
Pan2.ar
340-
(
338+
Pan2.ar(
341339
BLowPass.ar(Saw.ar(freq), freq * 8, 0.5),
342340
rrand(-0.5, 0.5),
343341
numVoices.reciprocal
344342
)
345-
}!numVoices);
346-
Out.ar(0, sig);
343+
}!numVoices);
344+
Out.ar(0, sig);
345+
}).writeDefFile(File.getcwd);
346+
347+
SynthDef(\DetectSilence, { arg out;
348+
var z;
349+
z = SinOsc.ar(Rand(400, 700), 0, LFDNoise3.kr(8).max(0)).softclip * 0.3;
350+
DetectSilence.ar(z, doneAction:2);
351+
Out.ar(out, z);
347352
}).writeDefFile(File.getcwd);
348353

349354
0.exit;

0 commit comments

Comments
 (0)