-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add first kit (hihat, snare, kick, crash) generated by my robot…
… friend
- Loading branch information
Showing
8 changed files
with
275 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,7 @@ | ||
import {useEffect, useState} from 'react'; | ||
import {Kit} from './Kit.tsx'; | ||
|
||
function App() { | ||
const [isLoading, setLoading] = useState(true); | ||
useEffect(() => { | ||
setTimeout(() => { | ||
setLoading(false); | ||
}, 2000); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
{ | ||
isLoading ? | ||
<img src="./icons/pwa-512x512.png" alt="loading" /> | ||
:<>kikoo</> | ||
} | ||
</> | ||
) | ||
return <Kit/>; | ||
} | ||
|
||
export default App | ||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import {playHiHat} from './samples/hihat.ts'; | ||
import {playSnare} from './samples/snare.ts'; | ||
import {playKick} from './samples/kick.ts'; | ||
import {playCrashCymbal} from './samples/crash.ts'; | ||
|
||
const buttonWidth = '49%'; | ||
const buttonHeight = '99%'; | ||
|
||
const buttonStyle = { | ||
width: buttonWidth, | ||
height: buttonHeight, | ||
color: 'white', | ||
border: 'none', | ||
borderRadius: '0', | ||
} | ||
|
||
export const Kit = () => { | ||
return <div style={{ | ||
width: '100%', | ||
height: '100vh', | ||
display: 'flex', | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
flexDirection: 'column', | ||
}}> | ||
<div style={{ | ||
display: 'flex', | ||
width: '100%', | ||
height: '50vh', | ||
flexDirection: 'row', | ||
}}> | ||
<button style={{...buttonStyle, backgroundColor: '#FDA341'}} onClick={() => playHiHat()}>HiHat</button> | ||
<button style={{...buttonStyle, backgroundColor: '#FE5156'}} onClick={() => playSnare()}>Snare</button> | ||
</div> | ||
|
||
<div style={{ | ||
display: 'flex', | ||
width: '100%', | ||
height: '50vh', | ||
flexDirection: 'row', | ||
}}> | ||
<button style={{...buttonStyle, backgroundColor: '#0BDAFE'}} onClick={() => playKick()}>Kick</button> | ||
<button style={{...buttonStyle, backgroundColor: '#C56BFE'}} onClick={() => playCrashCymbal()}>Crash</button> | ||
</div> | ||
|
||
</div> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// Create an Audio Context | ||
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); | ||
// | ||
// How It Works: | ||
// White Noise: The crash cymbal sound is built from a long burst of white noise (1.5 seconds) to capture the "wash" of the cymbal. | ||
// High-Pass Filter: We apply a high-pass filter with a high cutoff frequency (4000 Hz) to remove low-end noise and focus on the brighter, metallic part of the cymbal. | ||
// Low-Pass Filter: A low-pass filter at 12,000 Hz smooths out the very high frequencies, making the sound more pleasant and less harsh. | ||
// Gain Envelope: A long exponential decay simulates the ringing-out characteristic of a crash cymbal. | ||
// Metallic Overtones: A high-pitched oscillator (triangle wave) is added subtly to give the crash some metallic shimmer. | ||
// Customization: | ||
// Decay Time: You can adjust the decay time (currently 1.5 seconds) for a longer or shorter crash cymbal. | ||
// Filter Frequencies: Adjusting the high-pass and low-pass filter frequencies will change how bright or dark the cymbal sounds. | ||
// Oscillator Volume: The metallic shimmer is controlled by oscGain.gain. You can increase or decrease it to blend the overtone more or less with the noise. | ||
export function playCrashCymbal() { | ||
// --- 1. White Noise for the main crash sound --- | ||
const bufferSize = audioContext.sampleRate * 1.5; // 1.5 second buffer for long decay | ||
const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate); | ||
const output = noiseBuffer.getChannelData(0); | ||
|
||
for (let i = 0; i < bufferSize; i++) { | ||
output[i] = Math.random() * 2 - 1; // Generate white noise | ||
} | ||
|
||
const noise = audioContext.createBufferSource(); | ||
noise.buffer = noiseBuffer; | ||
|
||
// --- 2. High-pass filter to remove lower frequencies --- | ||
const highPassFilter = audioContext.createBiquadFilter(); | ||
highPassFilter.type = 'highpass'; | ||
highPassFilter.frequency.setValueAtTime(4000, audioContext.currentTime); // High cutoff for cymbal brightness | ||
|
||
// --- 3. Low-pass filter to shape the high-end frequencies --- | ||
const lowPassFilter = audioContext.createBiquadFilter(); | ||
lowPassFilter.type = 'lowpass'; | ||
lowPassFilter.frequency.setValueAtTime(12000, audioContext.currentTime); // Smooth out harsh high frequencies | ||
|
||
// --- 4. Gain envelope to control the crash sound decay --- | ||
const gainNode = audioContext.createGain(); | ||
gainNode.gain.setValueAtTime(1, audioContext.currentTime); // Start loud | ||
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 1.5); // Long decay (1.5 seconds) | ||
|
||
// Connect the nodes together: noise -> highPass -> lowPass -> gain -> output | ||
noise.connect(highPassFilter); | ||
highPassFilter.connect(lowPassFilter); | ||
lowPassFilter.connect(gainNode); | ||
gainNode.connect(audioContext.destination); | ||
|
||
// Play the noise | ||
noise.start(); | ||
noise.stop(audioContext.currentTime + 1.5); // Stop after 1.5 seconds | ||
|
||
// --- 5. Optional: Add metallic overtones using an oscillator --- | ||
const osc = audioContext.createOscillator(); | ||
osc.type = 'triangle'; // Triangle wave for metallic shimmer | ||
osc.frequency.setValueAtTime(10000, audioContext.currentTime); // High frequency for shimmer effect | ||
|
||
const oscGain = audioContext.createGain(); | ||
oscGain.gain.setValueAtTime(0.05, audioContext.currentTime); // Low volume to blend with noise | ||
oscGain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 1.5); // Decay along with noise | ||
|
||
// Connect oscillator for shimmer | ||
osc.connect(oscGain); | ||
oscGain.connect(audioContext.destination); | ||
|
||
osc.start(); | ||
osc.stop(audioContext.currentTime + 1.5); // Same duration as the noise | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
// Create an Audio Context | ||
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); | ||
|
||
// Improvements: | ||
// Shorter Noise Burst: The noise buffer duration is now much shorter (0.05 seconds), which results in a sharper, crisper hi-hat sound. | ||
// High-Pass Filter Tweaks: The cutoff frequency is set to 8000 Hz to eliminate more of the low-end and leave the high frequencies that give the hi-hat its metallic sound. | ||
// Resonance: Adding a slight resonance (Q = 1) to the high-pass filter emphasizes the higher frequencies and creates a sharper, more defined hi-hat. | ||
// Metallic Overtones: A very high-frequency square wave oscillator adds a metallic "shimmer" to the sound, blending with the noise. | ||
// Further Adjustments: | ||
// Decay: You can modify the decay time (currently 0.05 seconds for the noise and 0.03 for the oscillator) to make the hi-hat longer or shorter depending on whether you want a closed or open hi-hat. | ||
// Oscillator Volume: The oscillator (oscGain) is set at a low volume to subtly blend with the noise, creating a realistic metallic feel. | ||
// | ||
|
||
export function playHiHat() { | ||
// --- 1. White Noise (for metallic hiss) --- | ||
const bufferSize = audioContext.sampleRate * 0.05; // Very short burst for a hi-hat | ||
const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate); | ||
const output = noiseBuffer.getChannelData(0); | ||
|
||
for (let i = 0; i < bufferSize; i++) { | ||
output[i] = Math.random() * 2 - 1; // White noise | ||
} | ||
|
||
const noise = audioContext.createBufferSource(); | ||
noise.buffer = noiseBuffer; | ||
|
||
// High-pass filter to remove low frequencies and sharpen the sound | ||
const highPassFilter = audioContext.createBiquadFilter(); | ||
highPassFilter.type = 'highpass'; | ||
highPassFilter.frequency.setValueAtTime(8000, audioContext.currentTime); // High cutoff for a crisp sound | ||
highPassFilter.Q.setValueAtTime(1, audioContext.currentTime); // Slight resonance for metallic touch | ||
|
||
// Envelope to quickly fade out the noise | ||
const noiseGain = audioContext.createGain(); | ||
noiseGain.gain.setValueAtTime(1, audioContext.currentTime); | ||
noiseGain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.05); // Fast decay for hi-hat sound | ||
|
||
noise.connect(highPassFilter); | ||
highPassFilter.connect(noiseGain); | ||
noiseGain.connect(audioContext.destination); | ||
|
||
noise.start(); | ||
noise.stop(audioContext.currentTime + 0.05); // Short, sharp sound | ||
|
||
// --- 2. Additional metallic tone (optional, for a more "shimmering" hi-hat) --- | ||
const osc = audioContext.createOscillator(); | ||
osc.type = 'square'; // Square wave for more metallic sound | ||
osc.frequency.setValueAtTime(10000, audioContext.currentTime); // Very high frequency for shimmer | ||
|
||
const oscGain = audioContext.createGain(); | ||
oscGain.gain.setValueAtTime(0.1, audioContext.currentTime); // Low volume to blend with noise | ||
oscGain.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.03); // Fast decay | ||
|
||
osc.connect(oscGain); | ||
oscGain.connect(audioContext.destination); | ||
|
||
osc.start(); | ||
osc.stop(audioContext.currentTime + 0.03); // Short burst for shimmer | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Create an Audio Context | ||
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); | ||
|
||
// How It Works: | ||
// Low-Frequency Oscillator: We start with a sine wave, which provides the smooth, deep bass characteristic of a kick drum. | ||
// Frequency Envelope: The frequency starts at 150 Hz (giving it an initial "punch") and quickly decays to 60 Hz, giving the typical bass drum "thump." | ||
// Gain Envelope: The volume starts high and quickly decays over 0.5 seconds to simulate the fast attack and tail of a real kick drum. | ||
// Customization: | ||
// Pitch: Adjust the initial frequency (150 Hz) or the final frequency (60 Hz) to create different kinds of kicks (e.g., higher for more punch, lower for deeper bass). | ||
// Decay: The duration of the gain envelope can be adjusted to make the kick longer or shorter. | ||
|
||
export function playKick() { | ||
// Create an oscillator for the low "thump" | ||
const osc = audioContext.createOscillator(); | ||
osc.type = 'sine'; // Sine wave for a smooth, deep bass sound | ||
|
||
// Create a gain node to control the amplitude envelope | ||
const gainNode = audioContext.createGain(); | ||
|
||
// Frequency (pitch) envelope: Start higher and quickly decay to a lower frequency | ||
osc.frequency.setValueAtTime(150, audioContext.currentTime); // Initial higher frequency for punch | ||
osc.frequency.exponentialRampToValueAtTime(60, audioContext.currentTime + 0.1); // Drop to 60Hz | ||
|
||
// Gain envelope: Start loud and quickly decay | ||
gainNode.gain.setValueAtTime(1, audioContext.currentTime); // Start loud | ||
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + 0.5); // Decay to quiet over 0.5 seconds | ||
|
||
// Connect oscillator to gain, then to the audio context destination | ||
osc.connect(gainNode); | ||
gainNode.connect(audioContext.destination); | ||
|
||
// Start and stop the oscillator | ||
osc.start(); | ||
osc.stop(audioContext.currentTime + 0.5); // Stop after 0.5 seconds (length of the kick) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Create an Audio Context | ||
const audioContext = new (window.AudioContext || (window as any).webkitAudioContext)(); | ||
|
||
// Breakdown: | ||
// White Noise: | ||
// | ||
// Generates a burst of noise for the "rattle" effect of the snare wires. | ||
// A high-pass filter is applied to remove lower frequencies, leaving the sharper noise. | ||
// The noise fades out quickly using an envelope for a natural decay. | ||
// Low-Frequency Oscillator: | ||
// | ||
// A sine wave oscillator creates the low-pitched "thump" of the drum body. | ||
// This sound also decays quickly using an envelope to mimic the drumhead vibration stopping. | ||
// Envelope Control: | ||
// | ||
// Both the noise and oscillator have quick decay envelopes to simulate the natural sound of a snare hit. | ||
export function playSnare() { | ||
// --- 1. White Noise (for the snare wires) --- | ||
const bufferSize = audioContext.sampleRate * 0.2; // Duration: 0.2 seconds | ||
const noiseBuffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate); | ||
const output = noiseBuffer.getChannelData(0); | ||
|
||
for (let i = 0; i < bufferSize; i++) { | ||
output[i] = Math.random() * 2 - 1; // White noise | ||
} | ||
|
||
const noise = audioContext.createBufferSource(); | ||
noise.buffer = noiseBuffer; | ||
|
||
// Apply a high-pass filter to the noise | ||
const noiseFilter = audioContext.createBiquadFilter(); | ||
noiseFilter.type = 'highpass'; | ||
noiseFilter.frequency.setValueAtTime(1000, audioContext.currentTime); | ||
|
||
// Envelope for the noise | ||
const noiseGain = audioContext.createGain(); | ||
noiseGain.gain.setValueAtTime(1, audioContext.currentTime); | ||
noiseGain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.2); // Quick decay | ||
|
||
noise.connect(noiseFilter); | ||
noiseFilter.connect(noiseGain); | ||
noiseGain.connect(audioContext.destination); | ||
|
||
noise.start(); | ||
noise.stop(audioContext.currentTime + 0.2); // Short burst | ||
|
||
// --- 2. Low-Frequency Oscillator (for the drum body) --- | ||
const osc = audioContext.createOscillator(); | ||
osc.type = 'sine'; // Sine wave for low-pitched tone | ||
osc.frequency.setValueAtTime(150, audioContext.currentTime); // Low frequency (150 Hz for a snare body) | ||
|
||
const oscGain = audioContext.createGain(); | ||
oscGain.gain.setValueAtTime(0.7, audioContext.currentTime); | ||
oscGain.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); // Quick decay to mimic drum hit | ||
|
||
osc.connect(oscGain); | ||
oscGain.connect(audioContext.destination); | ||
|
||
osc.start(); | ||
osc.stop(audioContext.currentTime + 0.1); // Short, punchy tone | ||
} |