Skip to main content

A comprehensive Python framework for musical note processing, MIDI manipulation and music theory operations

Project description

SoundKit

A Comprehensive Python Framework for Musical Note Processing, MIDI Manipulation and Music Theory Operations

SoundKit is a powerful Python framework designed for musicians, developers, and audio engineers working with musical notes, MIDI data, and music theory. It provides intuitive APIs for note conversion, chord generation, scale creation, and comprehensive music theory operations.

Features

  • 🎵 Note Conversion: Convert between note names, MIDI numbers, and frequencies
  • 🎹 Chord Generation: Create chords with various types and inversions
  • 🎼 Scale Generation: Generate musical scales with multiple octaves
  • 🔍 Validation: Comprehensive input validation and error handling
  • 📊 Utilities: Advanced conversion tools and music theory utilities
  • 🎯 Music Theory: Built-in music theory operations and constants

Installation

pip install soundkit

Quick News!

Soundkit functions can now be used without specifying their parent modules first. Nonetheless, they can still be used with their parent modules to prevent older codebases from breaking.

import soundkit as sk

print(sk.midiFreq("C4")) # 60 (without the core.notes or notes moudule)
print(sk.notes.midiFreq("C4")) # 60 (with the notes module)

# It's still the same thing

Quick Start

import soundkit as sk

# Basic note conversion
print(sk.midiKey("C4"))      # 60
print(sk.midiFreq("A4"))     # 440.0

# Create chords
c_major = sk.get_chord_notes("C", "maj", 4)
print(c_major)  # [60, 64, 67]

# Generate scales
c_major_scale = sk.get_scale_notes("C", "major", 4, 2)
print(c_major_scale)  # [60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83]

Core Modules

Notes Module

The notes module handles all note-related conversions and operations.

Basic Note Conversion

import soundkit as sk

# Convert note name to MIDI number
midi_number = sk.midiKey("C4")        # 60
midi_number = sk.midiKey("A4")        # 69
midi_number = sk.midiKey("Gb3")       # 54

# Convert note name to frequency
frequency = sk.midiFreq("A4")         # 440.0
frequency = sk.midiFreq("C4")         # 261.63
frequency = sk.midiFreq("C4", round_digits=4)  # 261.6256

# Convert frequency to MIDI number
midi_number = sk.freqToMidi(440.0)    # 69
midi_number = sk.freqToMidi(261.63)   # 60

# Convert MIDI number to note name
note_name = sk.midiToNoteName(60)     # "C4"
note_name = sk.midiToNoteName(69)     # "A4"
note_name = sk.midiToNoteName(60, use_sharps=False)  # "C4" (no effect for C)

Supported Note Formats

SoundKit supports various note naming conventions:

# Sharp notes
sk.midiKey("C#4")    # 61
sk.midiKey("D#4")    # 63
sk.midiKey("F#4")    # 66

# Flat notes
sk.midiKey("Db4")    # 61
sk.midiKey("Eb4")    # 63
sk.midiKey("Gb4")    # 66

# Mixed notation
sk.midiKey("C4")     # 60
sk.midiKey("C#4")    # 61
sk.midiKey("Db4")    # 61 (same as C#4)

Batch Processing

import soundkit as sk

# Process multiple notes at once
notes = ["C4", "E4", "G4", "A4", "B4"]

# Convert to MIDI numbers
midi_numbers = sk.notes_to_midi(notes)
print(midi_numbers)  # [60, 64, 67, 69, 71]

# Convert to frequencies
frequencies = sk.notes_to_frequencies(notes)
print(frequencies)  # [261.63, 329.63, 392.0, 440.0, 493.88]

# With custom concert pitch
frequencies = sk.notes_to_frequencies(notes, concert_pitch=442.0)

Validation

import soundkit as sk

# Check if note is valid
is_valid = sk.is_valid_midi_range("C4")  # True
is_valid = sk.is_valid_midi_range("C11") # False

# Handle invalid notes gracefully
try:
    sk.notes.midiKey("H4")  # Invalid note
except sk.InvalidNoteError as e:
    print(f"Error: {e}")

try:
    sk.notes.midiKey("C11")  # Invalid octave
except sk.InvalidOctaveError as e:
    print(f"Error: {e}")

Chords Module

The chords module provides chord generation and manipulation.

Basic Chord Generation

import soundkit as sk

# Generate chord notes
c_major = sk.get_chord_notes("C", "maj", 4)
print(c_major)  # [60, 64, 67]

d_minor = sk.get_chord_notes("D", "min", 4)
print(d_minor)  # [62, 65, 69]

g_seventh = sk.get_chord_notes("G", "7", 4)
print(g_seventh)  # [67, 71, 74, 77]

Available Chord Types

import soundkit as sk

# Get all available chord types
chord_types = sk.get_chord_names()
print(chord_types)
# ['maj', 'major', 'min', 'minor', 'dim', 'diminished', 'aug', 'augmented', 
#  '7', 'dominant7', 'maj7', 'major7', 'min7', 'minor7', 'dim7', 'diminished7', 
#  'half_dim7', 'm7b5', 'sus2', 'sus4', '9', 'maj9']

Chord Inversions

import soundkit as sk

# Root position
c_major_root = sk.get_chord_notes("C", "maj", 4, inversion=0)
print(c_major_root)  # [60, 64, 67]

# First inversion
c_major_first = sk.get_chord_notes("C", "maj", 4, inversion=1)
print(c_major_first)  # [64, 67, 72]

# Second inversion
c_major_second = sk.get_chord_notes("C", "maj", 4, inversion=2)
print(c_major_second)  # [67, 72, 76]

Chord Frequencies

import soundkit as sk

# Get chord frequencies
c_major_freq = sk.get_chord_frequencies("C", "maj", 4)
print(c_major_freq)  # [261.63, 329.63, 392.0]

# With custom rounding
c_major_freq = sk.get_chord_frequencies("C", "maj", 4, round_digits=4)
print(c_major_freq)  # [261.6256, 329.6276, 392.0]

# With inversion
c_major_first_freq = sk.get_chord_frequencies("C", "maj", 4, inversion=1)

Scales Module

The scales module provides scale generation and music theory operations.

Basic Scale Generation

import soundkit as sk

# Generate scale notes
c_major = sk.get_scale_notes("C", "major", 4)
print(c_major)  # [60, 62, 64, 65, 67, 69, 71]

a_minor = sk.get_scale_notes("A", "minor", 4)
print(a_minor)  # [69, 71, 72, 74, 76, 77, 79]

# Multiple octaves
c_major_2octaves = sk.get_scale_notes("C", "major", 4, 2)
print(c_major_2octaves)  # [60, 62, 64, 65, 67, 69, 71, 72, 74, 76, 77, 79, 81, 83]

Available Scale Types

import soundkit as sk

# Get all available scale types
scale_types = sk.scales.get_scale_names()
print(scale_types)
# ['major', 'minor', 'natural_minor', 'harmonic_minor', 'melodic_minor', 
#  'pentatonic_major', 'pentatonic_minor', 'blues', 'dorian', 'phrygian', 
#  'lydian', 'mixolydian', 'locrian', 'whole_tone']

Scale Frequencies

import soundkit as sk

# Get scale frequencies
c_major_freq = sk.get_scale_frequencies("C", "major", 4)
print(c_major_freq)  # [261.63, 293.66, 329.63, 349.23, 392.0, 440.0, 493.88]

# Multiple octaves with custom rounding
c_major_2oct_freq = sk.scales.get_scale_frequencies("C", "major", 4, 2, round_digits=1)

Modes and Special Scales

import soundkit as sk

# Modes
d_dorian = sk.scales.get_scale_notes("D", "dorian", 4)
print(d_dorian)  # [62, 64, 65, 67, 69, 71, 72]

# Pentatonic scales
c_pentatonic_major = sk.scales.get_scale_notes("C", "pentatonic_major", 4)
print(c_pentatonic_major)  # [60, 62, 64, 67, 69]

a_pentatonic_minor = sk.scales.get_scale_notes("A", "pentatonic_minor", 4)
print(a_pentatonic_minor)  # [69, 72, 74, 76, 79]

# Blues scale
c_blues = sk.scales.get_scale_notes("C", "blues", 4)
print(c_blues)  # [60, 63, 65, 66, 67, 70]

Utils Module

The utils module provides validation and conversion utilities.

Validators

import soundkit as sk

# Note validation
is_valid = sk.validators.validate_note_name("C4")        # True
is_valid = sk.validators.validate_note_name("H4")        # False
is_valid = sk.validators.validate_note_name("C#4")       # True
is_valid = sk.validators.validate_note_name("Db4")       # True

# MIDI range validation
is_valid = sk.validators.validate_midi_range(60)         # True
is_valid = sk.validators.validate_midi_range(128)        # False

# Frequency validation
is_valid = sk.validators.validate_frequency(440.0)       # True
is_valid = sk.validators.validate_frequency(-10.0)       # False

# Octave validation
is_valid = sk.validators.validate_octave(4)              # True
is_valid = sk.validators.validate_octave(11)             # False

# Note normalization
normalized = sk.validators.normalize_note_name("c#4")    # "C#4"
normalized = sk.validators.normalize_note_name("db4")    # "DB4"
normalized = sk.validators.normalize_note_name("C ♯4")   # "C#4"

Converters

import soundkit as sk

# Frequency to cents
cents = sk.converters.frequency_to_cents(440, 444)       # ~15.67
cents = sk.converters.frequency_to_cents(440, 880)       # 1200.0

# Cents to ratio
ratio = sk.converters.cents_to_ratio(100)                # ~1.05946
ratio = sk.converters.cents_to_ratio(1200)               # 2.0

# Ratio conversions
ratio = sk.converters.semitones_to_ratio(12)             # 2.0
semitones = sk.converters.ratio_to_semitones(2.0)        # 12.0

# Frequency normalization
normalized = sk.converters.normalize_frequency(441.0)    # ~440.0
normalized = sk.converters.normalize_frequency(445.0, reference=442.0)

Constants

SoundKit provides useful musical constants:

import soundkit as sk

# Standard concert pitch
print(sk.CONCERT_PITCH)  # 440.0

# MIDI range
print(sk.MIDI_RANGE)     # (0, 127)

# Reference frequencies
print(sk.REFERENCE_FREQUENCIES["A4"])  # 440.0
print(sk.REFERENCE_FREQUENCIES["C4"])  # 261.63

# Use constants in your calculations
custom_freq = sk.notes.midiFreq("A4", concert_pitch=442.0)

Error Handling

SoundKit provides comprehensive error handling with custom exceptions:

import soundkit as sk

try:
    # Invalid note name
    sk.notes.midiKey("H4")
except sk.InvalidNoteError as e:
    print(f"Invalid note: {e}")

try:
    # Invalid octave
    sk.notes.midiKey("C11")
except sk.InvalidOctaveError as e:
    print(f"Invalid octave: {e}")

try:
    # Invalid frequency
    sk.notes.freqToMidi(-100)
except sk.InvalidFrequencyError as e:
    print(f"Invalid frequency: {e}")

try:
    # Invalid chord type
    sk.chords.get_chord_notes("C", "invalid_type", 4)
except sk.InvalidChordError as e:
    print(f"Invalid chord: {e}")

try:
    # Invalid scale type
    sk.scales.get_scale_notes("C", "invalid_scale", 4)
except sk.InvalidScaleError as e:
    print(f"Invalid scale: {e}")

Advanced Examples

Music Theory Application

import soundkit as sk

def analyze_progression(progression):
    """Analyze a chord progression"""
    for chord in progression:
        root, quality = chord
        notes = sk.chords.get_chord_notes(root, quality, 4)
        frequencies = sk.chords.get_chord_frequencies(root, quality, 4)
        print(f"{root}{quality}: {notes} -> {frequencies}Hz")

# Analyze a II-V-I progression
progression = [("D", "min7"), ("G", "7"), ("C", "maj7")]
analyze_progression(progression)

Scale Visualization

import soundkit as sk

def print_scale_intervals(root_note, scale_type, octave=4):
    """Print scale with note names and frequencies"""
    midi_notes = sk.scales.get_scale_notes(root_note, scale_type, octave)
    
    print(f"{root_note} {scale_type} scale:")
    for midi in midi_notes:
        note_name = sk.notes.midiToNoteName(midi)
        frequency = sk.notes.midiFreq(note_name)
        print(f"  {note_name}: {frequency}Hz")

print_scale_intervals("C", "major")
print_scale_intervals("A", "harmonic_minor")

Tuning Analysis

import soundkit as sk

def compare_tunings(note_name, reference_pitches):
    """Compare frequencies across different tuning standards"""
    print(f"Note: {note_name}")
    for name, pitch in reference_pitches.items():
        freq = sk.notes.midiFreq(note_name, concert_pitch=pitch)
        print(f"  {name} (A4={pitch}Hz): {freq}Hz")

tunings = {
    "Modern Standard": 440.0,
    "Baroque": 415.0,
    "Classical": 430.0,
    "Modern High": 442.0
}

compare_tunings("A4", tunings)

API Reference

Notes Module

  • midiKey(note_name: str) -> int: Convert note name to MIDI number
  • midiFreq(note_name: str, round_digits: int = 2, concert_pitch: float = 440.0) -> float: Convert note name to frequency
  • freqToMidi(frequency: float, concert_pitch: float = 440.0) -> int: Convert frequency to MIDI number
  • midiToNoteName(midi_number: int, use_sharps: bool = True) -> str: Convert MIDI number to note name
  • is_valid_midi_range(note_name: str) -> bool: Check if note is within MIDI range
  • notes_to_midi(note_list: List[str]) -> List[Union[int, str]]: Convert list of notes to MIDI numbers
  • notes_to_frequencies(note_list: List[str], round_digits: int = 2, concert_pitch: float = 440.0) -> List[Union[float, str]]: Convert list of notes to frequencies

Chords Module

  • get_chord_notes(chord_root: str, chord_type: str = 'maj', octave: int = 4, inversion: int = 0) -> List[int]: Get MIDI notes for a chord
  • get_chord_frequencies(chord_root: str, chord_type: str = 'maj', octave: int = 4, round_digits: int = 2, inversion: int = 0) -> List[float]: Get frequencies for a chord
  • get_chord_names() -> List[str]: Get available chord types

Scales Module

  • get_scale_notes(scale_root: str, scale_type: str = 'major', octave: int = 4, num_octaves: int = 1) -> List[int]: Get MIDI notes for a scale
  • get_scale_frequencies(scale_root: str, scale_type: str = 'major', octave: int = 4, num_octaves: int = 1, round_digits: int = 2) -> List[float]: Get frequencies for a scale
  • get_scale_names() -> List[str]: Get available scale types

Utils Module

Validators

  • validate_note_name(note_name: str) -> bool: Validate note name format
  • validate_midi_range(midi_number: int) -> bool: Validate MIDI number range
  • validate_frequency(frequency: float) -> bool: Validate frequency value
  • validate_octave(octave: int) -> bool: Validate octave range
  • normalize_note_name(note_name: str) -> str: Normalize note name format

Converters

  • frequency_to_cents(freq1: float, freq2: float) -> float: Convert frequency ratio to cents
  • cents_to_ratio(cents: float) -> float: Convert cents to frequency ratio
  • ratio_to_cents(ratio: float) -> float: Convert frequency ratio to cents
  • semitones_to_ratio(semitones: float) -> float: Convert semitones to frequency ratio
  • ratio_to_semitones(ratio: float) -> float: Convert frequency ratio to semitones
  • normalize_frequency(frequency: float, reference: float = 440.0) -> float: Normalize frequency to nearest reference

Contributing

We welcome contributions! Please see our Contributing Guide for details.

License

SoundKit is released under the MIT License. See LICENSE for details.

Support

For bug reports, feature requests, or questions:

Version History

  • 1.0.0: Initial release with core note, chord, and scale functionality
  • 1.0.5: Minor type corrections and updates

SoundKit is developed and maintained by Quabynah Davis.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

soundkit-1.0.5.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

soundkit-1.0.5-py3-none-any.whl (13.6 kB view details)

Uploaded Python 3

File details

Details for the file soundkit-1.0.5.tar.gz.

File metadata

  • Download URL: soundkit-1.0.5.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for soundkit-1.0.5.tar.gz
Algorithm Hash digest
SHA256 fe50a762b46316c4d923655abc3609f70f54a4070206c1c9660dcb563f393596
MD5 c1c30be7983f951596778b7f2d398ee9
BLAKE2b-256 40618ae0d828dbb5f5f9f696b9ac90786971d8fefeccb28c51307f4d71b94bc8

See more details on using hashes here.

File details

Details for the file soundkit-1.0.5-py3-none-any.whl.

File metadata

  • Download URL: soundkit-1.0.5-py3-none-any.whl
  • Upload date:
  • Size: 13.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for soundkit-1.0.5-py3-none-any.whl
Algorithm Hash digest
SHA256 a8540754a0b670ae329f445fbe9657f1c38c5f345af0a0df335af38a04e3d691
MD5 c36cd8d246ba8b8455f3acb68b6c73d1
BLAKE2b-256 0622c537e79077f8fca5dbe1e08eab7674e2637f14f06ea2050a21c5bbaa58bb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page