// drawFrequonsFourier draws the frequency-domain representation of Frequons. func drawFrequonsFourier(pm nimble.PixMap) { c := universe.Zoo h := harmonicStorage[:len(c)] var ampScale float32 if autoGain.Value { // Compute L1 norm of amplitudes norm := float32(0) for i := range c { norm += math32.Abs(c[i].Amplitude) } ampScale = 1 / norm } else { ampScale = 1 / float32(len(c)) } fracX, fracY := universe.BoxFraction() fracX *= zoomCompression fracY *= zoomCompression sizeX, sizeY := pm.Size() // Set up harmonics // (cx,cy) is center of fourier view cx, cy := 0.5*float32(sizeX)*fracX, 0.5*float32(sizeY)*fracY α, β := -0.5*cx, -0.5*cy ωScale := 200. / float32(sizeX*sizeY) for i := range h { ωx := (c[i].Sx - cx) * ωScale ωy := (c[i].Sy - cy) * ωScale h[i].Ωx = ωx h[i].Ωy = ωy h[i].Phase = α*ωx + β*ωy + phaseRoll // Scale amplitude so that DFT values fit within domain of color lookup table. h[i].Amplitude = c[i].Amplitude * ampScale } marginX := int32(math32.Round(0.5 * float32(sizeX) * (1 - fracX))) marginY := int32(math32.Round(0.5 * float32(sizeY) * (1 - fracY))) fourier.Draw(pm.Intersect(nimble.Rect{ Left: marginX, Right: sizeX - marginX, Top: marginY, Bottom: sizeY - marginY, }), h, universe.Scheme()) if marginX != 0 || marginY != 0 { pm.DrawRect(nimble.Rect{Left: 0, Right: sizeX, Top: 0, Bottom: marginY}, nimble.Black) pm.DrawRect(nimble.Rect{Left: 0, Right: sizeX, Top: sizeY - marginY, Bottom: sizeY}, nimble.Black) pm.DrawRect(nimble.Rect{Left: 0, Right: marginX, Top: marginY, Bottom: sizeY - marginY}, nimble.Black) pm.DrawRect(nimble.Rect{Left: sizeX - marginX, Right: sizeX, Top: marginY, Bottom: sizeY - marginY}, nimble.Black) } }
func init() { Twang = makeSound(44100, func(i float32) float32 { const ω = 110 * 2 * π / nimble.SampleRate const nharmonic = 32 sum := float32(0) for h := float32(1); h <= nharmonic; h++ { sum += math32.Sin(ω*h*i) * math32.Exp(-i*0.00004*h) } return sum / nharmonic }) n := len(Twang) AntiTwang = make([]float32, n) for i := range AntiTwang { AntiTwang[i] = Twang[n-1-i] } sum := float32(0) Broken = makeSound(44100, func(i float32) float32 { r := (rand.Float32() - 0.5) * (1.0 / 16) newSum := sum + r if math32.Abs(newSum) < 1.0 { sum = newSum } sum *= (1 - 1/32.0) return sum * math32.Exp(-i*.0001) }) Wobble = makeSound(44100, func(i float32) float32 { return 0.25 * math32.Sin((440+44*math32.Sin(i*0.001))*i*(2*π/nimble.SampleRate)) * math32.Exp(-i*0.00005) }) partials := [...]float32{0.56, 0.92, 1.19, 1.71, 2.00, 2.74, 3.00, 3.76, 4.07} Bell = makeSound(44100, func(i float32) float32 { const θ = 512 * 2 * π / nimble.SampleRate sum := float32(0) const n = float32(len(partials)) for j := range partials { sum += math32.Sin(i * θ * partials[j]) } return sum * (1.0 / n) * math32.Exp(-i*0.0001) }) }