From 0320d0b02530fb33eb15508bc3620221f814b11f Mon Sep 17 00:00:00 2001 From: Robin Haberkorn Date: Mon, 11 Dec 2023 03:46:54 +0300 Subject: added FFT Jupyter notebook * This still refers to a wave file that shouldn't be checked in. --- examples/fft.ipynb | 2154 ++++++++++++++++++++++++++++++++++++++++++++++++++++ examples/fft.lua | 2 +- 2 files changed, 2155 insertions(+), 1 deletion(-) create mode 100644 examples/fft.ipynb diff --git a/examples/fft.ipynb b/examples/fft.ipynb new file mode 100644 index 0000000..ff447f2 --- /dev/null +++ b/examples/fft.ipynb @@ -0,0 +1,2154 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4a93eae1-5c0e-4cf1-846a-621d0fcdd29e", + "metadata": {}, + "source": [ + "# Fast Fourier Transforms (FFT)\n", + "\n", + "Let $x_0, \\ldots, x_{n-1}$ be complex numbers. The [Discrete Fourier Transform (DFT)](https://en.wikipedia.org/wiki/Discrete-time_Fourier_transform) is defined by the formula:\n", + "\n", + "$$\n", + " X_k = \\sum_{m=0}^{n-1} x_m e^{-i2\\pi k m/n} \\qquad k = 0,\\ldots,n-1,\n", + "$$\n", + "\n", + "Let's define a stream, consisting of exactly 20 sine waves in 1024 samples:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "554cb334-283a-40c1-89aa-5fe1fd41161c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.005\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.015\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.02\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.025\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "sines = Stream.SinOsc(samplerate*20/1024):sub(1, 1024)\n", + "sines:gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "580e13a3-f910-472c-b887-76929aab1d87", + "metadata": {}, + "source": [ + "The bins of the corresponding frequency spectrum correspond to frequencies according to the following formula:\n", + "\n", + "$$\n", + " f_i = {i {f_{srate} \\over N}}\n", + "$$\n", + "\n", + "Plotting the frequency spectrum's magnitudes of `sines` should therefore give us a clear signal around bin 20 (Lua index 21).\n", + "\n", + "**NOTE:** This does not need windowing since the waves fit perfectly into 1024 sample buffer." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "02aec3d0-4ae9-4bcb-a034-764418b7827f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 0, 0, 1.173742634399e-14, 0, 0, 0, 3.9584680075211e-15, 0, 0, 0, 512, 0, 0, 0, 2.2315199565268e-14, 0, 0, 0, 8.6716166150709e-15, 0}\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.002\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.004\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.006\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.008\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.012\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "spectrum = tostream(magnitude(FFT(sines)))\n", + "print(spectrum:sub(10, 30))\n", + "spectrum:gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "7ca7e0b3-1854-41b4-813f-016eb148387e", + "metadata": {}, + "source": [ + "Testing the inverse FFT - looks just like the original wave:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e7fc0ea8-d510-41aa-815e-f29055f5b8e1", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.005\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.015\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.02\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.025\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "IFFT(FFT(sines)):gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "6c306c6e-dddc-4d8c-bac8-04f009c406df", + "metadata": {}, + "source": [ + "With 20.5 sines in the fragment, the plot is much better when applying a windowing function:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "03d8fa36-aad6-4de9-9866-1551c5010d25", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.002\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.004\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.006\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.008\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.012\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "tostream(magnitude(FFT(Hamming(Stream.SinOsc(samplerate*20.5/1024):sub(1, 1024))))):gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "c1e86db7-d3a6-4626-a71c-66bea1c04ae2", + "metadata": {}, + "source": [ + "Testing phase plotting. This is 20 sines but with phase 0.7 ($0.7 \\times 2\\pi$).\n", + "\n", + "**FIXME:** How exactly to interpret these numbers?" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "0d8e9009-255c-4840-b930-408eb3c419ed", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.9390625, 0, 0, 0, 0, 0, 0, 0, 0, 0}\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.002\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.004\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.006\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.008\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.012\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "spectrum = tostream(phase(FFT(Stream.SinOsc(samplerate*20/1024, 0.7):sub(1, 1024))))\n", + "print(spectrum:sub(10, 30))\n", + "spectrum:gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "12ed863d-99a4-4372-bb11-e0ce4b5013d3", + "metadata": {}, + "source": [ + "Let's try some naive real-time pitch shifting.\n", + "This however is [not easy to get right](https://www.reddit.com/r/DSP/comments/k6t24c/pitch_shifting_algorithm_in_frequency_domain/)!" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "bd0e1d6d-ad05-46dc-9701-92846bc8a683", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Buffer underrun detected\n" + ] + } + ], + "source": [ + "-- FIXME: Use a different sound file!\n", + "robin = SndfileStream(\"tracks/robin-mono.wav\"):sub(sec(10.284), sec(17.466)):eval()\n", + "robin:play()\n", + "robin:FFT(1024):map(function(spectrum)\n", + " assert(#spectrum == 513)\n", + " -- NOTE: We cannot use Stream:resample() as it won't work with complex samples.\n", + " for i = 1, 512/2 do spectrum[i] = spectrum[i*2] end\n", + " for i = 512/2+1, 512 do spectrum[i] = 0i end\n", + " return spectrum\n", + "end):IFFT(1024):play()" + ] + }, + { + "cell_type": "markdown", + "id": "cdf40dfb-b7ac-42ae-a6c3-178c7c8db1ff", + "metadata": {}, + "source": [ + "Let's generate and plot the spectrum of a sine mixed with some noise:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "58845a87-ed29-45e8-85c7-ac4b24013e5c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "Gnuplot\n", + "Produced by GNUPLOT 5.2 patchlevel 8 \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\t\n", + "\t \n", + "\t \n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t-0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.5\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 1\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.002\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.004\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.006\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.008\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.01\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\t\t\n", + "\t\t 0.012\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\tgnuplot_plot_1\n", + "\n", + "\t\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\t\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "metadata": { + "": "" + }, + "output_type": "display_data" + } + ], + "source": [ + "noisy = Stream.SinOsc(440):mix(NoiseStream, 0.4)\n", + "tostream(magnitude(FFT(Hamming(noisy:sub(1, 1024))))):mul(0.05):gnuplot()" + ] + }, + { + "cell_type": "markdown", + "id": "2141e582-948c-454e-834b-8148465e3869", + "metadata": {}, + "source": [ + "Try some very naive noise cancelling.\n", + "\n", + "**WARNING:** This plays indefinitely. Interrupt via Kernel → \"Interrupt Kernel\"." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "b43ca02e-16b8-4738-a157-db6dc1bb5b22", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Buffer underrun detected\n" + ] + }, + { + "ename": "n/a", + "evalue": "fft.lua:124: interrupted!", + "execution_count": 22, + "output_type": "error", + "traceback": [ + "fft.lua:124: interrupted!", + "stack traceback:", + "\tfft.lua:124: in function 'FFT_internal'", + "\tfft.lua:119: in function 'FFT_internal'", + "\tfft.lua:119: in function 'FFT_internal'", + "\tfft.lua:136: in function 'fnc'", + "\tapplause.lua:1871: in function 'tick'", + "\tapplause.lua:1870: in function 'tick'", + "\tapplause.lua:1870: in function 'stream_tick'", + "\tapplause.lua:1634: in function 'tick'", + "\tapplause.lua:726: in function ", + "\t[C]: in function 'xpcall'", + "\tapplause.lua:683: in function ", + "\t[C]: in function 'xpcall'", + "\t...ies/ilua/env/lib/python3.8/site-packages/ilua/interp.lua:65: in function 'handle_execute'", + "\t...ies/ilua/env/lib/python3.8/site-packages/ilua/interp.lua:176: in main chunk", + "stack traceback:", + "\t[C]: in function 'error'", + "\tapplause.lua:707: in function ", + "\t[C]: in function 'xpcall'", + "\t...ies/ilua/env/lib/python3.8/site-packages/ilua/interp.lua:65: in function 'handle_execute'", + "\t...ies/ilua/env/lib/python3.8/site-packages/ilua/interp.lua:176: in main chunk" + ] + } + ], + "source": [ + "noisy:FFT(1024, Hamming):map(function(spectrum)\n", + " assert(#spectrum == 513)\n", + " for i = 1, #spectrum do\n", + " if (spectrum[i].re^2 + spectrum[i].im^2)^.5*0.05 < 0.8 then spectrum[i] = 0i end\n", + " end\n", + " return spectrum\n", + "end):IFFT(1024):play()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc38550e-835c-47a8-a792-7164109dafee", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Lua", + "language": "lua", + "name": "lua" + }, + "language_info": { + "file_extension": ".lua", + "mimetype": "text/x-lua", + "name": "lua", + "version": "n/a" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/fft.lua b/examples/fft.lua index 85d0bc2..417f3c6 100644 --- a/examples/fft.lua +++ b/examples/fft.lua @@ -28,7 +28,7 @@ end):IFFT(1024):play() noisy = Stream.SinOsc(440):mix(NoiseStream, 0.4) tostream(magnitude(FFT(Hamming(noisy:sub(1, 1024))))):mul(0.05):gnuplot() --- Naive noise canceling +-- Naive noise cancelling noisy:FFT(1024, Hamming):map(function(spectrum) assert(#spectrum == 513) for i = 1, #spectrum do -- cgit v1.2.3