Skip to content

Added frequency augmentation #6

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

Merged
merged 1 commit into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions src/bundles/plotly/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
*/

import context from 'js-slang/context';
import Plotly, { type Data, type Layout } from 'plotly.js-dist';
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 {
FrequencySample,
AugmentedSample,
FrequencyList,
} from '../sound_fft/types';
import { generatePlot } from './curve_functions';
Expand Down Expand Up @@ -477,12 +477,12 @@ export const draw_sound_frequency_2d = (frequencies: FrequencyList) => {

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

for (let i = 0; i < len; i += 1) {
const bin_freq: number = i * FS / len;
const sample: FrequencySample = frequencies_arr[i];
const sample: AugmentedSample = frequencies_arr[i];
const magnitude: number = get_magnitude(sample);

x_s.push(bin_freq);
Expand Down
13 changes: 11 additions & 2 deletions src/bundles/plotly/sound_functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
is_pair
} from 'js-slang/dist/stdlib/list';
import { type Sound, type Wave } from '../sound/types';
import { type FrequencySample } from '../sound_fft/types';
import { type FrequencySample, type AugmentedSample } from '../sound_fft/types';
export function is_sound(x: any): x is Sound {
return (
is_pair(x)
Expand Down Expand Up @@ -38,6 +38,15 @@ export function get_duration(sound: Sound): number {
* @param frequency_sample given frequency sample
* @return the magnitude of the frequency sample
*/
export function get_magnitude(frequency_sample: FrequencySample): number {
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));
}
110 changes: 0 additions & 110 deletions src/bundles/sound/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@ import {
accumulate,
type List
} from 'js-slang/dist/stdlib/list';
import {
frequency_to_time,
time_to_frequency
} from '../sound_fft/functions';
import type {
TimeSamples,
FrequencySample,
FrequencySamples,
Filter
} from '../sound_fft/types';
import { RIFFWAVE } from './riffwave';
import type {
Wave,
Expand Down Expand Up @@ -317,58 +307,6 @@ export function play_wave(wave: Wave, duration: number): Sound {
return play(make_sound(wave, duration));
}

export function play_samples_in_tab(samples: TimeSamples): TimeSamples {
// Instantiate audio context if it has not been instantiated.
if (!audioplayer) {
init_audioCtx();
}

// Create mono buffer
const channel: number[] = [];
const len = samples.length;

let temp: number;
let prev_value = 0;

for (let i = 0; i < len; i += 1) {
temp = samples[i];
// clip amplitude
// channel[i] = temp > 1 ? 1 : temp < -1 ? -1 : temp;
if (temp > 1) {
channel[i] = 1;
} else if (temp < -1) {
channel[i] = -1;
} else {
channel[i] = temp;
}

// smoothen out sudden cut-outs
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
channel[i] = prev_value * 0.999;
}

prev_value = channel[i];
}

// quantize
for (let i = 0; i < channel.length; i += 1) {
channel[i] = Math.floor(channel[i] * 32767.999);
}

const riffwave = new RIFFWAVE([]);
riffwave.header.sampleRate = FS;
riffwave.header.numChannels = 1;
riffwave.header.bitsPerSample = 16;
riffwave.Make(channel);

const soundToPlay = {
toReplString: () => '<AudioPlayed>',
dataUri: riffwave.dataURI
};
audioPlayed.push(soundToPlay);
return samples;
}

/**
* Plays the given Sound using the computer’s sound device.
* The sound is added to a list of sounds to be played one-at-a-time
Expand Down Expand Up @@ -443,54 +381,6 @@ export function play_in_tab(sound: Sound): Sound {
}
}

export function play_samples(samples: TimeSamples): TimeSamples {
if (!audioplayer) {
init_audioCtx();
}

const theBuffer = audioplayer.createBuffer(
1,
samples.length,
FS
);
const channel = theBuffer.getChannelData(0);

let temp: number;
let prev_value = 0;

for (let i = 0; i < channel.length; i += 1) {
temp = samples[i];
// clip amplitude
if (temp > 1) {
channel[i] = 1;
} else if (temp < -1) {
channel[i] = -1;
} else {
channel[i] = temp;
}

// smoothen out sudden cut-outs
if (channel[i] === 0 && Math.abs(channel[i] - prev_value) > 0.01) {
channel[i] = prev_value * 0.999;
}

prev_value = channel[i];

}

// Connect data to output destination
const source = audioplayer.createBufferSource();
source.buffer = theBuffer;
source.connect(audioplayer.destination);
isPlaying = true;
source.start();
source.onended = () => {
source.disconnect(audioplayer.destination);
isPlaying = false;
};
return samples;
}

/**
* Plays the given Sound using the computer’s sound device
* on top of any Sounds that are currently playing.
Expand Down
6 changes: 1 addition & 5 deletions src/bundles/sound/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,5 @@ export {
stop,
triangle_sound,
trombone,
violin,
sound_to_time_samples,
play_samples_in_tab,
play_samples,
//play_filtered
violin
} from './functions';
61 changes: 37 additions & 24 deletions src/bundles/sound_fft/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import type {
TimeSamples,
FrequencySample,
AugmentedSample,
FrequencySamples,
FrequencyList,
Filter
Expand Down Expand Up @@ -59,8 +60,8 @@ export function frequency_to_time(frequency_samples: FrequencySamples): TimeSamp
const flatDomain = fft.createComplexArray();

for (let i = 0; i < n; i++) {
const magnitude = get_magnitude(frequency_samples[i]);
const phase = get_phase(frequency_samples[i]);
const magnitude = get_magnitude_fs(frequency_samples[i]);
const phase = get_phase_fs(frequency_samples[i]);
const real = magnitude * Math.cos(phase);
const imag = magnitude * Math.sin(phase);
flatDomain[i * 2] = real;
Expand Down Expand Up @@ -112,16 +113,16 @@ export function time_samples_to_sound(time_samples: TimeSamples): Sound {

function frequency_to_list(frequency_samples: FrequencySamples): FrequencyList {
const len = frequency_samples.length;
const augmented_samples: any[] = new Array(len);
const augmented_samples: AugmentedSample[] = new Array(len);
for (let i = 0; i < len; i++) {
augmented_samples[i] = pair(pair(i * FS / len, (i+1) * FS / len), frequency_samples[i]);
augmented_samples[i] = pair(i * FS / len, frequency_samples[i]);
}
const frequency_list: FrequencyList = vector_to_list(augmented_samples);
return frequency_list;
}

function list_to_frequency(frequency_list: FrequencyList): FrequencySamples {
const augmented_samples: any[] = list_to_vector(frequency_list);
const augmented_samples: AugmentedSample[] = list_to_vector(frequency_list);
const frequency_samples: FrequencySamples = new Array(augmented_samples.length);
for (let i = 0; i < augmented_samples.length; i++) {
frequency_samples[i] = tail(augmented_samples[i]);
Expand All @@ -143,29 +144,43 @@ export function frequency_to_sound(frequency_list: FrequencyList): Sound {
return sound;
}

// MAGNITUDE and PHASE
// FREQUENCY, MAGNITUDE and PHASE

export function get_magnitude(frequency_sample: FrequencySample): number {
function get_magnitude_fs(frequency_sample: FrequencySample): number {
return head(frequency_sample);
}

export function get_phase(frequency_sample: FrequencySample): number {
function get_phase_fs(frequency_sample: FrequencySample): number {
return tail(frequency_sample);
}

export function get_frequency(augmented_sample: AugmentedSample): number {
return head(augmented_sample);
}

export function get_magnitude(augmented_sample: AugmentedSample): number {
return get_magnitude_fs(tail(augmented_sample));
}

export function get_phase(augmented_sample: AugmentedSample): number {
return get_phase_fs(tail(augmented_sample));
}

export function make_augmented_sample(frequency: number, magnitude: number, phase: number): AugmentedSample {
return pair(frequency, pair(magnitude, phase));
}

// FILTER CREATION

export function low_pass_filter(frequency: number): Filter {
return (freqList: FrequencyList) => {
const freqDomain = list_to_vector(freqList);
const freqDomain: AugmentedSample[] = list_to_vector(freqList);
for (let i = 0; i < freqDomain.length; i++) {
if (head(head(freqDomain[i])) > frequency) {
freqDomain[i] = pair(
head(freqDomain[i]), // Frequency range
pair(
0, // Magnitude
tail(tail(freqDomain[i])) // Phase
)
if (get_frequency(freqDomain[i]) > frequency) {
freqDomain[i] = make_augmented_sample(
get_frequency(freqDomain[i]),
0,
get_phase(freqDomain[i])
);
}
}
Expand All @@ -175,15 +190,13 @@ export function low_pass_filter(frequency: number): Filter {

export function high_pass_filter(frequency: number): Filter {
return (freqList: FrequencyList) => {
const freqDomain = list_to_vector(freqList);
const freqDomain: AugmentedSample[] = list_to_vector(freqList);
for (let i = 0; i < freqDomain.length; i++) {
if (tail(head(freqDomain[i])) < frequency) {
freqDomain[i] = pair(
head(freqDomain[i]), // Frequency range
pair(
0, // Magnitude
tail(tail(freqDomain[i])) // Phase
)
if (get_frequency(freqDomain[i]) < frequency) {
freqDomain[i] = make_augmented_sample(
get_frequency(freqDomain[i]),
0,
get_phase(freqDomain[i])
);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/bundles/sound_fft/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export {

get_magnitude,
get_phase,
get_frequency,
make_augmented_sample,

frequency_to_sound,
sound_to_frequency,
Expand Down
3 changes: 2 additions & 1 deletion src/bundles/sound_fft/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { Pair, List } from 'js-slang/dist/stdlib/list';

export type TimeSamples = Array<number>;
export type FrequencySample = Pair<number, number>;
export type AugmentedSample = Pair<number, FrequencySample>;
export type FrequencySamples = Array<FrequencySample>;
export type FrequencyList = List;
export type FrequencyList = List; // containing AugmentedSample
export type Filter = (freq: FrequencyList) => FrequencyList;