-
Notifications
You must be signed in to change notification settings - Fork 0
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
Feature/mixer #1
base: master
Are you sure you want to change the base?
Changes from all commits
5f98b8b
4c004a1
4b47ec6
9c81def
2728c86
bbb5e32
96a026e
fb5fee8
100ad13
64fc253
93a697b
17af0f3
796d332
60823f4
c53b29c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/.vscode/ | ||
/samples/ | ||
*.wav |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package compressor | ||
|
||
//Compressor interface for sound compressor's | ||
type Compressor interface { | ||
Compress(notCompressedSound float64) float64 | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package compressor | ||
|
||
//DynamicRangeCompressor can process operation that reduces the volume of loud sounds | ||
//Treadshold it is a volume-level above which it is necessary to begin compression | ||
//Attack it is a delay for begin compression after exceeding the threshold | ||
//release it is a time while compression will work | ||
//compretionRatio it is a coefficient by which the signal will be multiplied | ||
type DynamicRangeCompressor struct { | ||
threshold float64 | ||
attack int | ||
release int | ||
compretionRatio float64 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
attackTimer int | ||
releaseTimer int | ||
|
||
isInitialize bool | ||
thresholHasBeenExceeded bool | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} | ||
|
||
//NewDynamicRangeCompressor creates new DynamicRangeCompressor to process sounds | ||
func NewDynamicRangeCompressor(threshold, compretionRatio float64, attack, release int) *DynamicRangeCompressor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's convenient to use a struct instead of obscure parameter lists:
|
||
return &DynamicRangeCompressor{ | ||
threshold: threshold, | ||
attack: attack, | ||
attackTimer: attack, | ||
release: release, | ||
compretionRatio: compretionRatio, | ||
isInitialize: true, | ||
} | ||
} | ||
|
||
//Compress sound | ||
func (d *DynamicRangeCompressor) Compress(notCompressedSound float64) float64 { | ||
|
||
if d == nil || !d.isInitialize { | ||
panic("dynamicRangeCOmpressor must be initialized. Use NewCompressor function") | ||
} | ||
|
||
compressedSound := notCompressedSound | ||
|
||
if notCompressedSound > d.threshold { | ||
d.releaseTimer = d.release | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can |
||
d.thresholHasBeenExceeded = true | ||
} | ||
|
||
if d.attackTimer == 0 && d.releaseTimer == 0 && d.thresholHasBeenExceeded { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it's possible to do this without |
||
d.attackTimer = d.attack | ||
d.thresholHasBeenExceeded = false | ||
compressedSound = d.compressFunction(notCompressedSound) | ||
|
||
} else if d.attackTimer == 0 && d.releaseTimer > 0 { | ||
compressedSound = d.compressFunction(notCompressedSound) | ||
d.releaseTimer-- | ||
|
||
} else if d.thresholHasBeenExceeded { | ||
d.attackTimer-- | ||
} | ||
|
||
return compressedSound | ||
} | ||
|
||
func (d *DynamicRangeCompressor) compressFunction(notCompressedSound float64) float64 { | ||
return notCompressedSound * d.compretionRatio | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package compressor | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("DynamicRangeCompressor", func() { | ||
|
||
It("Should return same value", func() { | ||
|
||
compressor := NewDynamicRangeCompressor(2.0, 0.5, 1, 2) | ||
|
||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
Expect(0.5).To(Equal(compressor.Compress(0.5))) | ||
}) | ||
|
||
It("Should return compresed value with attack delay", func() { | ||
compressor := NewDynamicRangeCompressor(1.9, 0.5, 1, 2) | ||
|
||
Expect(2.0).To(Equal(compressor.Compress(2.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(2.0))) | ||
Expect(0.5).To(Equal(compressor.Compress(1.0))) | ||
Expect(0.5).To(Equal(compressor.Compress(1.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
}) | ||
|
||
It("Should return compresed value without attack delay", func() { | ||
compressor := NewDynamicRangeCompressor(1.9, 0.5, 0, 2) | ||
|
||
Expect(1.0).To(Equal(compressor.Compress(2.0))) | ||
Expect(0.5).To(Equal(compressor.Compress(1.0))) | ||
Expect(0.5).To(Equal(compressor.Compress(1.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
Expect(5.0).To(Equal(compressor.Compress(10.0))) | ||
Expect(0.5).To(Equal(compressor.Compress(1.0))) | ||
}) | ||
|
||
It("Should return compresed value without attack delay and witout release delay", func() { | ||
compressor := NewDynamicRangeCompressor(1.9, 0.5, 0, 0) | ||
|
||
Expect(1.0).To(Equal(compressor.Compress(2.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(2.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
Expect(5.0).To(Equal(compressor.Compress(10.0))) | ||
Expect(1.0).To(Equal(compressor.Compress(1.0))) | ||
}) | ||
}) | ||
|
||
func TestCompressor(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "Compressor Suite") | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package compressor | ||
|
||
//MockCompressorImpl this is mock for interface Compressor. Hi does nothing. | ||
type MockCompressorImpl struct { | ||
} | ||
|
||
//Compress just return same value | ||
func (m MockCompressorImpl) Compress(notCompressedSound float64) float64 { | ||
return notCompressedSound | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Go interfaces are usually defined in user packages. So
Mixer
should define what it accepts as aCompressor
.