Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Feature Extraction

This notebook extracts acoustic features from crowd sound stimuli using librosa.

Features extracted per sound:

  • Duration

  • Global intensity (RMS)

  • F0 (pitch) mean and variability (YIN algorithm)

  • Spectral centroid, bandwidth, rolloff

  • MFCC (13 coefficients)

Results are saved as outputs/<sound_name>/results.json.

Imports

import os
import json
import numpy as np
import librosa

Configuration

audio_folder = "../data/sounds"
output_folder = "../outputs"
os.makedirs(output_folder, exist_ok=True)

print("Audio files found:", os.listdir(audio_folder))
Audio files found: ['A22.wav', 'A23.wav', 'A15.wav', 'J4.wav', 'A3.wav', 'A11.wav', 'J3.wav', 'A21.wav', 'J6.wav', 'A14.wav', 'J12.wav', 'J15.wav', 'J7.wav', 'J23.wav', 'A12.wav', 'J8.wav', 'J1.wav', 'J13.wav', 'A2.wav', 'J9.wav', 'J18.wav', 'J20.wav', 'A8.wav', 'A7.wav', 'A19.wav', 'A24.wav', 'J11.wav', 'A1.wav', 'A9.wav', 'A17.wav', 'A5.wav', 'A16.wav', 'J26.wav', 'J5.wav', 'A4.wav', 'J21.wav', 'A20.wav', 'A18.wav', 'J2.wav', 'J10.wav', 'J24.wav', 'A25.wav', 'A6.wav', 'J16.wav', 'J25.wav', 'J14.wav', 'A26.wav', 'A13.wav', 'J17.wav', 'J22.wav', 'A10.wav', 'J19.wav']

Feature Extraction Loop

results = {}

for file in sorted(os.listdir(audio_folder)):
    if not file.endswith(".wav"):
        continue

    path = os.path.join(audio_folder, file)
    audio, sr = librosa.load(path, sr=None)
    print(f"\nProcessing: {file} ({len(audio)/sr:.2f}s)")

    # Duration
    duration = len(audio) / sr

    # Intensity (RMS)
    rms = librosa.feature.rms(y=audio)
    global_intensity = float(np.mean(rms))

    # F0 (pitch) via YIN
    f0 = librosa.yin(audio, fmin=50, fmax=500)
    f0_mean = float(np.nanmean(f0))
    f0_var = float(np.nanstd(f0))

    # Spectral features
    spectral_centroid = librosa.feature.spectral_centroid(y=audio, sr=sr)
    spectral_bandwidth = librosa.feature.spectral_bandwidth(y=audio, sr=sr)
    spectral_rolloff = librosa.feature.spectral_rolloff(y=audio, sr=sr)
    mfcc = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=13)

    # Build result dict
    result = {
        "file": file,
        "duration": float(duration),
        "global_intensity": global_intensity,
        "f0_mean": f0_mean,
        "f0_variability": f0_var,
        "spectral_centroid_mean": float(np.mean(spectral_centroid)),
        "spectral_bandwidth_mean": float(np.mean(spectral_bandwidth)),
        "spectral_rolloff_mean": float(np.mean(spectral_rolloff)),
        "mfcc_mean": mfcc.mean(axis=1).tolist()
    }

    # Save JSON
    sound_name = file.replace(".wav", "")
    sound_output_folder = os.path.join(output_folder, sound_name)
    os.makedirs(sound_output_folder, exist_ok=True)
    json_path = os.path.join(sound_output_folder, "results.json")
    with open(json_path, "w") as f:
        json.dump(result, f, indent=4)

    results[file] = result
    print(f"  Saved: {json_path}")

print("\nDONE — all files processed")

Processing: A1.wav (1.50s)
  Saved: ../outputs/A1/results.json

Processing: A10.wav (1.50s)
  Saved: ../outputs/A10/results.json

Processing: A11.wav (1.50s)
  Saved: ../outputs/A11/results.json

Processing: A12.wav (1.50s)
  Saved: ../outputs/A12/results.json

Processing: A13.wav (1.50s)
  Saved: ../outputs/A13/results.json

Processing: A14.wav (1.50s)
  Saved: ../outputs/A14/results.json

Processing: A15.wav (1.50s)
  Saved: ../outputs/A15/results.json

Processing: A16.wav (1.50s)
  Saved: ../outputs/A16/results.json

Processing: A17.wav (1.50s)
  Saved: ../outputs/A17/results.json

Processing: A18.wav (1.50s)
  Saved: ../outputs/A18/results.json

Processing: A19.wav (1.50s)
  Saved: ../outputs/A19/results.json

Processing: A2.wav (1.50s)
  Saved: ../outputs/A2/results.json

Processing: A20.wav (1.50s)
  Saved: ../outputs/A20/results.json

Processing: A21.wav (1.50s)
  Saved: ../outputs/A21/results.json

Processing: A22.wav (1.50s)
  Saved: ../outputs/A22/results.json

Processing: A23.wav (1.50s)
  Saved: ../outputs/A23/results.json

Processing: A24.wav (1.50s)
  Saved: ../outputs/A24/results.json

Processing: A25.wav (1.50s)
  Saved: ../outputs/A25/results.json

Processing: A26.wav (1.50s)
  Saved: ../outputs/A26/results.json

Processing: A3.wav (1.50s)
  Saved: ../outputs/A3/results.json

Processing: A4.wav (1.51s)
  Saved: ../outputs/A4/results.json

Processing: A5.wav (1.51s)
  Saved: ../outputs/A5/results.json

Processing: A6.wav (1.50s)
  Saved: ../outputs/A6/results.json

Processing: A7.wav (1.50s)
  Saved: ../outputs/A7/results.json

Processing: A8.wav (1.50s)
  Saved: ../outputs/A8/results.json

Processing: A9.wav (1.50s)
  Saved: ../outputs/A9/results.json

Processing: J1.wav (1.50s)
  Saved: ../outputs/J1/results.json

Processing: J10.wav (1.50s)
  Saved: ../outputs/J10/results.json

Processing: J11.wav (1.50s)
  Saved: ../outputs/J11/results.json

Processing: J12.wav (1.50s)
  Saved: ../outputs/J12/results.json

Processing: J13.wav (1.50s)
  Saved: ../outputs/J13/results.json

Processing: J14.wav (1.50s)
  Saved: ../outputs/J14/results.json

Processing: J15.wav (1.50s)
  Saved: ../outputs/J15/results.json

Processing: J16.wav (1.50s)
  Saved: ../outputs/J16/results.json

Processing: J17.wav (1.50s)
  Saved: ../outputs/J17/results.json

Processing: J18.wav (1.50s)
  Saved: ../outputs/J18/results.json

Processing: J19.wav (1.50s)
  Saved: ../outputs/J19/results.json

Processing: J2.wav (1.50s)
  Saved: ../outputs/J2/results.json

Processing: J20.wav (1.50s)
  Saved: ../outputs/J20/results.json

Processing: J21.wav (1.50s)
  Saved: ../outputs/J21/results.json

Processing: J22.wav (1.50s)
  Saved: ../outputs/J22/results.json

Processing: J23.wav (1.50s)
  Saved: ../outputs/J23/results.json

Processing: J24.wav (1.50s)
  Saved: ../outputs/J24/results.json

Processing: J25.wav (1.50s)
  Saved: ../outputs/J25/results.json

Processing: J26.wav (1.50s)
  Saved: ../outputs/J26/results.json

Processing: J3.wav (1.50s)
  Saved: ../outputs/J3/results.json

Processing: J4.wav (1.50s)
  Saved: ../outputs/J4/results.json

Processing: J5.wav (1.50s)
  Saved: ../outputs/J5/results.json

Processing: J6.wav (1.50s)
  Saved: ../outputs/J6/results.json

Processing: J7.wav (1.50s)
  Saved: ../outputs/J7/results.json

Processing: J8.wav (1.50s)
  Saved: ../outputs/J8/results.json

Processing: J9.wav (1.50s)
  Saved: ../outputs/J9/results.json

DONE — all files processed

Summary

print(f"Total sounds processed: {len(results)}")
for name, r in results.items():
    print(f"  {name}: duration={r['duration']:.2f}s, F0={r['f0_mean']:.1f}Hz, intensity={r['global_intensity']:.4f}")
Total sounds processed: 52
  A1.wav: duration=1.50s, F0=298.0Hz, intensity=0.0459
  A10.wav: duration=1.50s, F0=192.6Hz, intensity=0.0419
  A11.wav: duration=1.50s, F0=134.0Hz, intensity=0.0407
  A12.wav: duration=1.50s, F0=158.1Hz, intensity=0.0441
  A13.wav: duration=1.50s, F0=165.5Hz, intensity=0.0436
  A14.wav: duration=1.50s, F0=196.8Hz, intensity=0.0469
  A15.wav: duration=1.50s, F0=177.6Hz, intensity=0.0400
  A16.wav: duration=1.50s, F0=188.0Hz, intensity=0.0398
  A17.wav: duration=1.50s, F0=153.1Hz, intensity=0.0382
  A18.wav: duration=1.50s, F0=232.2Hz, intensity=0.0349
  A19.wav: duration=1.50s, F0=256.9Hz, intensity=0.0386
  A2.wav: duration=1.50s, F0=183.3Hz, intensity=0.0464
  A20.wav: duration=1.50s, F0=317.2Hz, intensity=0.0382
  A21.wav: duration=1.50s, F0=160.0Hz, intensity=0.0411
  A22.wav: duration=1.50s, F0=119.1Hz, intensity=0.0379
  A23.wav: duration=1.50s, F0=120.4Hz, intensity=0.0821
  A24.wav: duration=1.50s, F0=173.6Hz, intensity=0.0400
  A25.wav: duration=1.50s, F0=193.2Hz, intensity=0.0379
  A26.wav: duration=1.50s, F0=186.9Hz, intensity=0.0372
  A3.wav: duration=1.50s, F0=233.5Hz, intensity=0.0469
  A4.wav: duration=1.51s, F0=184.0Hz, intensity=0.0465
  A5.wav: duration=1.51s, F0=165.1Hz, intensity=0.0479
  A6.wav: duration=1.50s, F0=342.6Hz, intensity=0.0455
  A7.wav: duration=1.50s, F0=247.8Hz, intensity=0.0458
  A8.wav: duration=1.50s, F0=278.8Hz, intensity=0.0455
  A9.wav: duration=1.50s, F0=237.3Hz, intensity=0.0421
  J1.wav: duration=1.50s, F0=278.6Hz, intensity=0.0384
  J10.wav: duration=1.50s, F0=226.4Hz, intensity=0.0289
  J11.wav: duration=1.50s, F0=294.6Hz, intensity=0.0242
  J12.wav: duration=1.50s, F0=362.6Hz, intensity=0.0238
  J13.wav: duration=1.50s, F0=363.8Hz, intensity=0.0446
  J14.wav: duration=1.50s, F0=297.0Hz, intensity=0.0451
  J15.wav: duration=1.50s, F0=306.6Hz, intensity=0.0465
  J16.wav: duration=1.50s, F0=306.0Hz, intensity=0.0332
  J17.wav: duration=1.50s, F0=364.4Hz, intensity=0.0390
  J18.wav: duration=1.50s, F0=232.2Hz, intensity=0.0425
  J19.wav: duration=1.50s, F0=138.7Hz, intensity=0.0451
  J2.wav: duration=1.50s, F0=211.4Hz, intensity=0.0411
  J20.wav: duration=1.50s, F0=364.4Hz, intensity=0.0390
  J21.wav: duration=1.50s, F0=443.3Hz, intensity=0.0361
  J22.wav: duration=1.50s, F0=419.0Hz, intensity=0.0360
  J23.wav: duration=1.50s, F0=389.9Hz, intensity=0.0350
  J24.wav: duration=1.50s, F0=440.3Hz, intensity=0.0450
  J25.wav: duration=1.50s, F0=289.2Hz, intensity=0.0419
  J26.wav: duration=1.50s, F0=441.0Hz, intensity=0.0459
  J3.wav: duration=1.50s, F0=198.5Hz, intensity=0.0401
  J4.wav: duration=1.50s, F0=218.9Hz, intensity=0.0410
  J5.wav: duration=1.50s, F0=250.3Hz, intensity=0.0438
  J6.wav: duration=1.50s, F0=293.0Hz, intensity=0.0405
  J7.wav: duration=1.50s, F0=233.3Hz, intensity=0.0468
  J8.wav: duration=1.50s, F0=135.3Hz, intensity=0.0437
  J9.wav: duration=1.50s, F0=291.2Hz, intensity=0.0470