Skip to content

Sound processing using FFT #375

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

Draft
wants to merge 34 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
245f8d5
PoC for FFT modification
Unknown15082 Feb 19, 2025
8b827d0
Working FFT modification function
Unknown15082 Mar 4, 2025
8c31386
playFFT function
Unknown15082 Mar 18, 2025
881f706
new sound_fft module, doesnt even work yet
Unknown15082 Mar 25, 2025
1991046
still does not work, cannot import sound_fft
Unknown15082 Mar 25, 2025
609aa26
added minimal buggy example
press-sutart Mar 26, 2025
b45041c
Merge pull request #2 from Unknown15082/stot
press-sutart Mar 26, 2025
3457d4c
Working play_filtered, play_samples and other filter-related functions
Unknown15082 Apr 1, 2025
0024111
Move (real, imag) to (magnitude, phase)
Unknown15082 Apr 1, 2025
91080d7
Conversion methods
Unknown15082 Apr 1, 2025
3ea8030
Added play_samples_in_tab
press-sutart Apr 2, 2025
050a3cf
Added methods to plot time-domain and frequency-domain samples in plo…
press-sutart Apr 2, 2025
beb83d3
Remove trailing spaces
press-sutart Apr 2, 2025
dcdc9e8
Merge pull request #3 from Unknown15082/stot
press-sutart Apr 2, 2025
efb7f0e
Added direct conversions between Sound and FrequencyList in sound_fft
press-sutart Apr 6, 2025
16f5f10
Merge pull request #4 from Unknown15082/stot
press-sutart Apr 6, 2025
2aa1593
Changed draw_sound_frequency_2d to accept FrequencyList and removed d…
press-sutart Apr 6, 2025
0846935
Merge pull request #5 from Unknown15082/stot
press-sutart Apr 6, 2025
0cabe2b
WIP: low_pass_filter not running with large lists
Unknown15082 Apr 7, 2025
9f6c872
Working filter_sound, low_pass_filter. Augmented FrequencyList to inc…
Unknown15082 Apr 8, 2025
49e0cdc
Added frequency augmentation
press-sutart Apr 8, 2025
aa24a3a
Merge pull request #6 from Unknown15082/stot
press-sutart Apr 8, 2025
abfd361
Fixed issue where long sounds cannot be converted to frequencies
press-sutart Apr 9, 2025
e944920
Merge pull request #7 from Unknown15082/stot
press-sutart Apr 10, 2025
7fe38f9
made low_pass_filter and high_pass_filter symmetric
press-sutart Apr 12, 2025
ab59256
Merge branch 'master' into stot
press-sutart Apr 12, 2025
75a1d20
Made low_pass_filter and high_pass_filter symmetric
press-sutart Apr 12, 2025
0710d3f
Merge source-academy/modules/master
press-sutart Apr 14, 2025
bce075a
Merge pull request #9 from Unknown15082/stot
press-sutart Apr 14, 2025
21a7075
Merge branch 'master' into master
press-sutart Apr 14, 2025
a6a1f13
added 44100 points limit to plotly sound drawing functions
press-sutart Apr 15, 2025
37d2d17
Merge pull request #10 from Unknown15082/stot
press-sutart Apr 15, 2025
d5c3594
added documentation to sound_fft and fixed some in plotly
press-sutart Apr 15, 2025
f666f61
Merge pull request #11 from Unknown15082/stot
press-sutart Apr 15, 2025
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
5 changes: 4 additions & 1 deletion modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"Sound"
]
},
"sound_fft": {
"tabs": []
},
"scrabble": {
"tabs": []
},
Expand Down Expand Up @@ -122,4 +125,4 @@
"Unittest"
]
}
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"@jscad/stl-serializer": "2.1.11",
"ace-builds": "^1.25.1",
"classnames": "^2.3.1",
"fft.js": "^4.0.4",
"gl-matrix": "^3.3.0",
"js-slang": "^1.0.81",
"lodash": "^4.17.21",
Expand Down
99 changes: 89 additions & 10 deletions src/bundles/plotly/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
*/

import context from 'js-slang/context';
import { list_to_vector } from 'js-slang/dist/stdlib/list';
import Plotly, { type Data, type Layout } from 'plotly.js-dist';
import type { Sound } from '../sound/types';
import type {
AugmentedSample,
FrequencyList,
} from '../sound_fft/types';
import { generatePlot } from './curve_functions';
import {
type Curve,
Expand All @@ -14,7 +19,7 @@
DrawnPlot,
type ListOfPairs
} from './plotly';
import { get_duration, get_wave, is_sound } from './sound_functions';
import { get_duration, get_wave, is_sound, get_magnitude } from './sound_functions';

const drawnPlots: (CurvePlot | DrawnPlot)[] = [];

Expand Down Expand Up @@ -355,10 +360,10 @@

/**
* Returns a function that turns a given Curve into a Drawing, by sampling the
* Curve at num sample points. The Drawing consists of isolated points, and does not connect them.
* When a program evaluates to a Drawing, the Source system displays it graphically, in a window,
* Curve at `num` sample points. The Drawing consists of isolated points, and does not connect them.
* When a program evaluates to a Drawing, the Source system displays it graphically, in a window.
*
* * @param num determines the number of points, lower than 65535, to be sampled.
* @param num determines the number of points, lower than 65535, to be sampled.
* Including 0 and 1, there are `num + 1` evenly spaced sample points
* @return function of type 2D Curve → Drawing
* @example
Expand All @@ -380,10 +385,10 @@

/**
* Returns a function that turns a given 3D Curve into a Drawing, by sampling the
* 3D Curve at num sample points. The Drawing consists of isolated points, and does not connect them.
* When a program evaluates to a Drawing, the Source system displays it graphically, in a window,
* 3D Curve at `num` sample points. The Drawing consists of isolated points, and does not connect them.
* When a program evaluates to a Drawing, the Source system displays it graphically, in a window.
*
* * @param num determines the number of points, lower than 65535, to be sampled.
* @param num determines the number of points, lower than 65535, to be sampled.
* Including 0 and 1, there are `num + 1` evenly spaced sample points
* @return function of type 3D Curve → Drawing
* @example
Expand All @@ -397,11 +402,12 @@
);

/**
* Visualizes the sound on a 2d line graph
* Visualizes the given sound on a 2D line graph (amplitude vs time).
* @param sound the sound which is to be visualized on plotly
*/
export const draw_sound_2d = (sound: Sound) => {
const FS: number = 44100; // Output sample rate
const POINT_LIMIT: number = 44100; // Maximum number of points to be plotted
if (!is_sound(sound)) {
throw new Error(
`draw_sound_2d is expecting sound, but encountered ${sound}`
Expand All @@ -425,10 +431,19 @@

const x_s: number[] = [];
const y_s: number[] = [];

for (let i = 0; i < channel.length; i += 1) {
const insert_point = (i: number) => {
x_s.push(time_stamps[i]);
y_s.push(channel[i]);
};

if (channel.length <= POINT_LIMIT) {
for (let i = 0; i < channel.length; i += 1) {
insert_point(i);
}
} else {
for (let i = 0; i < POINT_LIMIT; i += 1) {
insert_point(Math.round(channel.length / POINT_LIMIT * i));
}
}

const plotlyData: Data = {
Expand Down Expand Up @@ -463,6 +478,70 @@
}
};

/**
* Visualizes the frequency-domain samples of the given sound on a 2D line graph
* (magnitude vs frequency).
* @param frequencies the frequency-domain samples of a sound to be visualized on plotly
*/
export const draw_sound_frequency_2d = (frequencies: FrequencyList) => {
const FS: number = 44100; // Output sample rate
const POINT_LIMIT: number = 44100; // Maximum number of points to be plotted

const x_s: number[] = [];
const y_s: number[] = [];
const frequencies_arr: AugmentedSample[] = list_to_vector(frequencies);
const len: number = frequencies_arr.length;

const insert_point = (i: number) => {
const bin_freq: number = i * FS / len;
const sample: AugmentedSample = frequencies_arr[i];
const magnitude: number = get_magnitude(sample);

x_s.push(bin_freq);
y_s.push(magnitude);
}

Check warning on line 502 in src/bundles/plotly/functions.ts

View workflow job for this annotation

GitHub Actions / Verify all tests pass and build success

Missing semicolon

if (len <= POINT_LIMIT) {
for (let i = 0; i < len; i += 1) {
insert_point(i);
}
} else {
for (let i = 0; i < POINT_LIMIT; i += 1) {
insert_point(Math.round(len / POINT_LIMIT * i));
}
}

const plotlyData: Data = {
x: x_s,
y: y_s
};
const plot = new CurvePlot(
draw_new_curve,
{
...plotlyData,
type: 'scattergl',
mode: 'lines',
line: { width: 0.5 }
} as Data,
{
xaxis: {
type: 'linear',
title: 'Frequency',
anchor: 'y',
position: 0,
rangeslider: { visible: true }
},
yaxis: {
type: 'linear',
visible: false
},
bargap: 0.2,
barmode: 'stack'
}
);
if (drawnPlots) drawnPlots.push(plot);
};

function draw_new_curve(divId: string, data: Data, layout: Partial<Layout>) {
Plotly.react(divId, [data], layout);
}
3 changes: 2 additions & 1 deletion src/bundles/plotly/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ export {
draw_connected_3d,
draw_points_2d,
draw_points_3d,
draw_sound_2d
draw_sound_2d,
draw_sound_frequency_2d
} from './functions';
19 changes: 19 additions & 0 deletions src/bundles/plotly/sound_functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
is_pair
} from 'js-slang/dist/stdlib/list';
import type { Sound, Wave } from '../sound/types';
import type { FrequencySample, AugmentedSample } from '../sound_fft/types';
export function is_sound(x: any): x is Sound {
return (
is_pair(x)
Expand Down Expand Up @@ -31,3 +32,21 @@ export function get_wave(sound: Sound): Wave {
export function get_duration(sound: Sound): number {
return tail(sound);
}
/**
* Accesses the magnitude of a given frequency sample.
*
* @param frequency_sample given frequency sample
* @return the magnitude of the frequency sample
*/
function get_magnitude_fs(frequency_sample: FrequencySample): number {
return head(frequency_sample);
}
/**
* Accesses the magnitude of a given augmented sample.
*
* @param augmented_sample given augmented sample
* @return the magnitude of the augmented sample
*/
export function get_magnitude(augmented_sample: AugmentedSample): number {
return get_magnitude_fs(tail(augmented_sample));
}
2 changes: 1 addition & 1 deletion src/bundles/sound/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
Sound,
SoundProducer,
SoundTransformer,
AudioPlayed
AudioPlayed,
} from './types';

// Global Constants and Variables
Expand Down
Loading
Loading