π Sample Library
10K+ Royalty-Free Samples with AI-Powered Search
π― Library Strategy
FlowState includes a curated library of real samples from legendary hardware. No synthesis approximations - authentic sounds from the actual machines that defined hip-hop.
Professional Quality: Real samples from TR-808, MPC-60, SP-1200, and more. The same sounds behind 50 Cent, Dr. Dre, Kanye, and every major hip-hop producer.
π Classic Sound Machines - Priority Tier List
Based on hit records, genre coverage, user demand, and royalty-free availability.
S-TIER: Essential (Must Have)
| Machine | Era | Iconic Producers | Status |
|---|---|---|---|
| Roland TR-808 | All Eras | Dr. Dre, Kanye, Metro Boomin, 808 Mafia | β Implemented |
| Akai MPC-60/3000 | Golden Era | DJ Premier, J Dilla, Pete Rock, RZA | β Implemented |
| E-mu SP-1200 | Golden Era | RZA, MF Doom, Madlib, Pete Rock | β Implemented |
A-TIER: High Priority
| Machine | Type | Use Case | Status |
|---|---|---|---|
| Roland TR-909 | Drums | Punchy electronic, house crossover | π Phase 2 |
| Yamaha DX7 | Keys | E PIANO 1, bells, 80s sounds | π Phase 2 |
| Fender Rhodes | Keys | Neo-soul, jazz-hop, chords | π Phase 2 |
| Korg M1/Triton | Workstation | 90s/2000s hip-hop, G-Funk | π Phase 2 |
B-TIER: Nice to Have
| Machine | Type | Status |
|---|---|---|
| Moog Minimoog | Synth Bass | π Phase 3 |
| Ensoniq ASR-10 | Sampler | π Phase 3 |
| LinnDrum | Drums | π Phase 3 |
| Oberheim DMX | Drums | π Phase 3 |
π Implementation Roadmap
Phase 1: Essential Foundation (Current)
- β TR-808 (Real) - 16 professional samples from TriSamples
- π MPC-60/3000 - Samples From Mars Free MPC60
- π SP-1200 - 12-bit golden era crunch
Coverage: Golden Era β Modern Trap (90%+ user demand)
Phase 2: Expanded Palette
- TR-909 - Tight electronic drums
- DX7 - Classic 80s keys
- Rhodes - Neo-soul electric piano
- Korg M1 - 90s workstation sounds
Coverage: Melodic instruments, 100% genre coverage
Phase 3: Specialization
- Minimoog - Analog bass/leads
- ASR-10 - Underground hip-hop
- LinnDrum - Vintage 80s
- Complete vintage collection
Business Case: One-time effort to curate and upload royalty-free samples. Users get studio-quality sounds without buying plugins. FlowState becomes a serious production tool, not a toy.
π΅ Why Real Samples Matter
| Aspect | Synthesis | Real Samples |
|---|---|---|
| Sound Quality | Approximation of analog warmth | Authentic hardware character |
| Producer Recognition | Generic electronic sounds | Sounds producers know and trust |
| Competitive Position | Same as free DAWs | Pro-quality library = differentiation |
| User Perception | "Toy" for beginners | Serious production tool |
π Sample Sources
| Source | Samples | License | Quality |
|---|---|---|---|
| Government Sound Library | 10,000+ | Public Domain | Variable |
| Freesound.org (curated) | 2,000+ | CC0 | Good |
| NASA Sound Library | 500+ | Public Domain | Unique |
| BBC Sound Effects | 16,000+ | Remix allowed | Excellent |
| Custom Recorded | 500+ | Original | Excellent |
ποΈ Sample Categories
| Category | Subcategories | Est. Count |
|---|---|---|
| Drums | Kicks, Snares, Hats, Claps, Percussion, Loops | 3,000 |
| Bass | 808s, Sub Bass, Synth Bass, Acoustic | 500 |
| Melodic | Keys, Strings, Pads, Leads, Plucks | 1,500 |
| Vocals | Chops, Ad-libs, FX, Chants | 800 |
| FX | Risers, Impacts, Transitions, Textures | 1,200 |
| Foley | Ambient, Nature, Urban, Mechanical | 3,000 |
π AI-Powered Search
Samples are indexed with semantic embeddings for natural language search.
Search Examples
| Query | Results |
|---|---|
| "dark trap snare" | Filtered snares with dark/distorted character |
| "something like Travis Scott" | Reverby 808s, ambient pads, auto-tune style |
| "punchy kick 90bpm" | Tempo-matched kicks with transient impact |
| "ethereal melody F minor" | Key-matched melodic samples |
Search Implementation
// sample-search.ts
interface Sample {
id: string;
name: string;
category: string;
tags: string[];
bpm: number | null;
key: string | null;
duration: number;
waveformPeaks: number[];
embedding: number[]; // 768-dim BGE embedding
url: string;
}
async function searchSamples(query: string, filters?: SearchFilters) {
// Generate embedding for query
const queryEmbedding = await env.AI.run('@cf/baai/bge-base-en-v1.5', {
text: query
});
// Search Vectorize index
const results = await env.SAMPLES_INDEX.query(queryEmbedding.data[0], {
topK: 20,
filter: buildFilter(filters)
});
// Fetch full sample metadata
const samples = await Promise.all(
results.matches.map(m => env.DB.prepare(
'SELECT * FROM samples WHERE id = ?'
).bind(m.id).first())
);
return samples;
}
function buildFilter(filters?: SearchFilters): VectorizeFilter {
const conditions: any = {};
if (filters?.category) {
conditions.category = { $eq: filters.category };
}
if (filters?.bpmRange) {
conditions.bpm = {
$gte: filters.bpmRange[0],
$lte: filters.bpmRange[1]
};
}
if (filters?.key) {
conditions.key = { $eq: filters.key };
}
return conditions;
}
π Sample Metadata Schema
-- D1 Schema
CREATE TABLE samples (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
filename TEXT NOT NULL,
category TEXT NOT NULL,
subcategory TEXT,
tags TEXT, -- JSON array
-- Audio properties
duration_ms INTEGER NOT NULL,
bpm REAL,
key TEXT,
sample_rate INTEGER DEFAULT 44100,
bit_depth INTEGER DEFAULT 16,
channels INTEGER DEFAULT 2,
-- Analysis
loudness_lufs REAL,
peak_db REAL,
spectral_centroid REAL,
-- Display
waveform_peaks TEXT, -- JSON array for visualization
color TEXT, -- Category color hint
-- Metadata
source TEXT, -- e.g., "government", "freesound", "user"
license TEXT,
attribution TEXT,
-- Storage
r2_key TEXT NOT NULL,
file_size INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_samples_category ON samples(category);
CREATE INDEX idx_samples_bpm ON samples(bpm);
CREATE INDEX idx_samples_key ON samples(key);
π΅ Audio Analysis Pipeline
Samples are analyzed on upload to extract metadata automatically.
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Upload β β Analyze β β Embed β β Index β
β Sample βββββΆβ Audio βββββΆβ Tags βββββΆβ Store β
β (R2) β β (Worker) β β (AI) β β (D1+Vec) β
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
Analysis Functions
| Analysis | Method | Output |
|---|---|---|
| BPM Detection | Essentia.js / Web Audio | Float (e.g., 140.5) |
| Key Detection | Chroma analysis | String (e.g., "F#m") |
| Loudness | LUFS calculation | Float (e.g., -14.2) |
| Waveform Peaks | Downsampled max values | Array[100] |
| Category | AI classification | String (e.g., "drums/kick") |
| Embedding | BGE text encoder | Float[768] |
// analyze-sample.ts
async function analyzeSample(audioBuffer: ArrayBuffer): Promise<SampleAnalysis> {
const audioContext = new OfflineAudioContext(2, 44100 * 30, 44100);
const buffer = await audioContext.decodeAudioData(audioBuffer);
// Extract features
const channelData = buffer.getChannelData(0);
return {
duration_ms: Math.round(buffer.duration * 1000),
sample_rate: buffer.sampleRate,
channels: buffer.numberOfChannels,
waveform_peaks: computePeaks(channelData, 100),
loudness_lufs: calculateLUFS(channelData, buffer.sampleRate),
peak_db: calculatePeakDb(channelData),
bpm: await detectBPM(channelData, buffer.sampleRate),
key: await detectKey(channelData, buffer.sampleRate)
};
}
function computePeaks(data: Float32Array, numPeaks: number): number[] {
const peaks: number[] = [];
const samplesPerPeak = Math.floor(data.length / numPeaks);
for (let i = 0; i < numPeaks; i++) {
let max = 0;
const start = i * samplesPerPeak;
for (let j = start; j < start + samplesPerPeak && j < data.length; j++) {
max = Math.max(max, Math.abs(data[j]));
}
peaks.push(max);
}
return peaks;
}
π¦ Storage Architecture
| Storage | Content | Access Pattern |
|---|---|---|
| R2 (samples/) | Audio files (WAV/MP3) | CDN cached, range requests |
| R2 (waveforms/) | Pre-rendered waveform images | CDN cached |
| D1 | Sample metadata | Filtered queries |
| Vectorize | Semantic embeddings | Similarity search |
R2 Key Structure
samples/
library/ # Built-in samples
drums/
kicks/
808-deep-01.wav
808-punchy-01.wav
snares/
hats/
melodic/
fx/
user/ # User uploads
{user_id}/
{sample_id}.wav
temp/ # Processing queue
{job_id}.wav
ποΈ Sample Browser UI
The sample browser provides multiple ways to find sounds.
UI Components
- Search Bar: Natural language + filters
- Category Tree: Hierarchical navigation
- Tag Cloud: Quick tag filtering
- Waveform Preview: Visual + hover-to-play
- Drag-to-Timeline: Direct placement
- Favorites: Quick access list
- Recent: Recently used samples
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Space | Preview selected sample |
| Enter | Add to current track |
| β/β | Navigate list |
| Cmd/Ctrl + F | Focus search |
| F | Toggle favorite |
π€ User Uploads
Users can upload their own samples to their personal library.
| Tier | Storage Limit | Max File Size |
|---|---|---|
| Free | 100MB | 10MB |
| Pro | 5GB | 50MB |
| Enterprise | 50GB | 200MB |
Upload Flow
// upload.ts
async function uploadSample(file: File, userId: string) {
// Validate
if (!['audio/wav', 'audio/mp3', 'audio/mpeg'].includes(file.type)) {
throw new Error('Unsupported format');
}
// Check quota
const usage = await getUserStorageUsage(userId);
if (usage + file.size > getUserStorageLimit(userId)) {
throw new Error('Storage quota exceeded');
}
// Generate ID and key
const sampleId = crypto.randomUUID();
const r2Key = `samples/user/${userId}/${sampleId}.wav`;
// Upload to R2
await env.SAMPLES_BUCKET.put(r2Key, file.stream());
// Analyze async
await env.ANALYSIS_QUEUE.send({
sampleId,
r2Key,
userId
});
return { sampleId, status: 'processing' };
}
π° Cost Breakdown
| Component | Cost (10K users) |
|---|---|
| R2 Storage (library) | $1.50 (100GB @ $0.015/GB) |
| R2 Storage (user uploads) | $7.50 (500GB) |
| Vectorize (5M vectors) | $0 (free tier) |
| D1 Database | $0 (free tier) |
| Workers AI (embeddings) | $2.00 |
| Total | ~$11/mo |
R2 Advantage: Zero egress fees mean sample streaming is essentially free regardless of how many times samples are previewed.