or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

format-export.mdindex.mdmidi-operations.mdmusic-theory-core.mdmusical-containers.md

musical-containers.mddocs/

0

# Musical Containers

1

2

Data structures for representing and manipulating musical information at different hierarchical levels - from individual notes to complete compositions. These classes store and organize musical data for analysis, manipulation, and playback.

3

4

## Capabilities

5

6

### Note Class

7

8

Represents a single musical note with pitch, octave, dynamics, and MIDI properties.

9

10

```python { .api }

11

class Note:

12

"""Single musical note with pitch and performance attributes."""

13

14

def __init__(self, name: str = "C", octave: int = 4, dynamics: Any = None, velocity: int = None, channel: int = None):

15

"""

16

Create Note object.

17

18

Parameters:

19

- name: Note name (e.g., "C", "F#", "Bb")

20

- octave: Octave number (typically 0-9)

21

- dynamics: Dynamic marking (pp, p, mp, mf, f, ff, etc.)

22

- velocity: MIDI velocity (0-127)

23

- channel: MIDI channel (1-16)

24

"""

25

26

@property

27

def name(self) -> str:

28

"""Note name (e.g., "C#")."""

29

30

@property

31

def octave(self) -> int:

32

"""Octave number."""

33

34

@property

35

def dynamics(self) -> Any:

36

"""Dynamic marking."""

37

38

@property

39

def velocity(self) -> int:

40

"""MIDI velocity (0-127)."""

41

42

@property

43

def channel(self) -> int:

44

"""MIDI channel (1-16)."""

45

46

def set_note(self, name: str = "C", octave: int = 4, dynamics: Any = None, velocity: int = None, channel: int = None) -> None:

47

"""

48

Set note properties.

49

50

Parameters:

51

- name: Note name

52

- octave: Octave number

53

- dynamics: Dynamic marking

54

- velocity: MIDI velocity

55

- channel: MIDI channel

56

"""

57

58

def empty(self) -> None:

59

"""Clear note to default values."""

60

61

def augment(self) -> None:

62

"""Augment note (raise by semitone)."""

63

64

def diminish(self) -> None:

65

"""Diminish note (lower by semitone)."""

66

67

def transpose(self, interval: str, up: bool = True) -> None:

68

"""

69

Transpose note by interval.

70

71

Parameters:

72

- interval: Interval to transpose (e.g., "3", "5", "b7")

73

- up: Direction (True for up, False for down)

74

"""

75

76

def change_octave(self, diff: int) -> None:

77

"""

78

Change octave by difference.

79

80

Parameters:

81

- diff: Octave difference (positive or negative)

82

"""

83

84

def octave_up(self) -> None:

85

"""Move up one octave."""

86

87

def octave_down(self) -> None:

88

"""Move down one octave."""

89

90

def to_hertz(self, standard_pitch: float = 440) -> float:

91

"""

92

Convert to frequency in Hz.

93

94

Parameters:

95

- standard_pitch: A4 frequency reference

96

97

Returns:

98

Frequency in Hz

99

"""

100

101

def from_hertz(self, hertz: float, standard_pitch: float = 440) -> None:

102

"""

103

Set note from frequency.

104

105

Parameters:

106

- hertz: Frequency in Hz

107

- standard_pitch: A4 frequency reference

108

"""

109

110

def measure(self, other: 'Note') -> int:

111

"""

112

Measure interval to other note in half steps.

113

114

Parameters:

115

- other: Other Note object

116

117

Returns:

118

Interval in half steps

119

"""

120

121

def to_shorthand(self) -> str:

122

"""

123

Convert to shorthand notation.

124

125

Returns:

126

Shorthand notation string

127

"""

128

129

def from_shorthand(self, shorthand: str) -> None:

130

"""

131

Set from shorthand notation.

132

133

Parameters:

134

- shorthand: Shorthand notation string

135

"""

136

```

137

138

### NoteContainer Class

139

140

Container for holding multiple notes, representing chords, intervals, or simultaneous note combinations.

141

142

```python { .api }

143

class NoteContainer:

144

"""Container for multiple notes (chords, intervals)."""

145

146

def __init__(self, notes: List[Union[str, Note]] = None):

147

"""

148

Create NoteContainer.

149

150

Parameters:

151

- notes: List of note names or Note objects

152

"""

153

154

def empty(self) -> None:

155

"""Empty container of all notes."""

156

157

def add_note(self, note: Union[str, Note], octave: int = None, dynamics: Any = None) -> bool:

158

"""

159

Add note to container.

160

161

Parameters:

162

- note: Note name or Note object

163

- octave: Octave for note name

164

- dynamics: Dynamic marking

165

166

Returns:

167

True if note was added successfully

168

"""

169

170

def add_notes(self, notes: List[Union[str, Note]]) -> None:

171

"""

172

Add multiple notes to container.

173

174

Parameters:

175

- notes: List of note names or Note objects

176

"""

177

178

def remove_note(self, note: Union[str, Note], octave: int = -1) -> bool:

179

"""

180

Remove note from container.

181

182

Parameters:

183

- note: Note name or Note object to remove

184

- octave: Specific octave to remove (-1 for any)

185

186

Returns:

187

True if note was removed

188

"""

189

190

def remove_notes(self, notes: List[Union[str, Note]]) -> None:

191

"""

192

Remove multiple notes from container.

193

194

Parameters:

195

- notes: List of notes to remove

196

"""

197

198

def from_chord(self, shorthand: str) -> bool:

199

"""

200

Create container from chord shorthand.

201

202

Parameters:

203

- shorthand: Chord shorthand (e.g., "CM7", "Am", "F#dim")

204

205

Returns:

206

True if chord was created successfully

207

"""

208

209

def from_interval(self, startnote: str, shorthand: str, up: bool = True) -> bool:

210

"""

211

Create container from interval.

212

213

Parameters:

214

- startnote: Starting note

215

- shorthand: Interval shorthand (e.g., "3", "5", "b7")

216

- up: Direction (True for up, False for down)

217

218

Returns:

219

True if interval was created successfully

220

"""

221

222

def determine(self, shorthand: bool = False) -> str:

223

"""

224

Determine chord name.

225

226

Parameters:

227

- shorthand: Return shorthand notation

228

229

Returns:

230

Chord name or description

231

"""

232

233

def sort(self) -> None:

234

"""Sort notes by pitch (lowest to highest)."""

235

236

def transpose(self, interval: str, up: bool = True) -> None:

237

"""

238

Transpose all notes by interval.

239

240

Parameters:

241

- interval: Interval to transpose

242

- up: Direction (True for up, False for down)

243

"""

244

245

def augment(self) -> None:

246

"""Augment all notes."""

247

248

def diminish(self) -> None:

249

"""Diminish all notes."""

250

251

def is_consonant(self, include_fourths: bool = True) -> bool:

252

"""

253

Test if container contains consonant intervals.

254

255

Parameters:

256

- include_fourths: Include perfect fourths as consonant

257

258

Returns:

259

True if all intervals are consonant

260

"""

261

262

def is_dissonant(self, include_fourths: bool = False) -> bool:

263

"""

264

Test if container contains dissonant intervals.

265

266

Parameters:

267

- include_fourths: Include perfect fourths as dissonant

268

269

Returns:

270

True if any intervals are dissonant

271

"""

272

273

def get_note_names(self) -> List[str]:

274

"""

275

Get list of note names.

276

277

Returns:

278

List of note names in container

279

"""

280

281

def remove_duplicate_notes(self) -> None:

282

"""Remove duplicate notes from container."""

283

```

284

285

### Bar Class

286

287

Represents a musical bar/measure containing notes with durations and timing information.

288

289

```python { .api }

290

class Bar:

291

"""Musical bar/measure with notes and timing."""

292

293

def __init__(self, key: str = "C", meter: Tuple[int, int] = (4, 4)):

294

"""

295

Create Bar object.

296

297

Parameters:

298

- key: Key signature

299

- meter: Time signature (numerator, denominator)

300

"""

301

302

@property

303

def key(self) -> str:

304

"""Key signature."""

305

306

@property

307

def meter(self) -> Tuple[int, int]:

308

"""Time signature tuple."""

309

310

def empty(self) -> None:

311

"""Empty bar of all notes."""

312

313

def set_meter(self, meter: Tuple[int, int]) -> None:

314

"""

315

Set time signature.

316

317

Parameters:

318

- meter: Time signature tuple

319

"""

320

321

def place_notes(self, notes: Union[str, List[str], Note, NoteContainer], duration: int) -> bool:

322

"""

323

Place notes with duration in bar.

324

325

Parameters:

326

- notes: Notes to place (various formats accepted)

327

- duration: Note duration (1=whole, 2=half, 4=quarter, etc.)

328

329

Returns:

330

True if notes were placed successfully

331

"""

332

333

def place_notes_at(self, notes: Union[str, List[str], Note, NoteContainer], at: float) -> bool:

334

"""

335

Place notes at specific position in bar.

336

337

Parameters:

338

- notes: Notes to place

339

- at: Position in bar (0.0 to 1.0)

340

341

Returns:

342

True if notes were placed successfully

343

"""

344

345

def place_rest(self, duration: int) -> bool:

346

"""

347

Place rest with duration.

348

349

Parameters:

350

- duration: Rest duration

351

352

Returns:

353

True if rest was placed successfully

354

"""

355

356

def is_full(self) -> bool:

357

"""

358

Check if bar is full.

359

360

Returns:

361

True if bar contains a full measure worth of notes/rests

362

"""

363

364

def space_left(self) -> float:

365

"""

366

Get remaining space in bar.

367

368

Returns:

369

Remaining space as fraction (0.0 to 1.0)

370

"""

371

372

def value_left(self) -> int:

373

"""

374

Get remaining value in bar.

375

376

Returns:

377

Remaining note value

378

"""

379

380

def remove_last_entry(self) -> bool:

381

"""

382

Remove last entry from bar.

383

384

Returns:

385

True if entry was removed

386

"""

387

388

def transpose(self, interval: str, up: bool = True) -> None:

389

"""

390

Transpose all notes in bar.

391

392

Parameters:

393

- interval: Interval to transpose

394

- up: Direction (True for up, False for down)

395

"""

396

397

def augment(self) -> None:

398

"""Augment all notes in bar."""

399

400

def diminish(self) -> None:

401

"""Diminish all notes in bar."""

402

403

def determine_chords(self, shorthand: bool = False) -> List[str]:

404

"""

405

Determine chords in bar.

406

407

Parameters:

408

- shorthand: Return shorthand notation

409

410

Returns:

411

List of chord names

412

"""

413

414

def determine_progression(self, shorthand: bool = False) -> List[str]:

415

"""

416

Determine chord progression in bar.

417

418

Parameters:

419

- shorthand: Return shorthand notation

420

421

Returns:

422

List of chord progressions

423

"""

424

425

def get_range(self) -> Tuple[Note, Note]:

426

"""

427

Get note range in bar.

428

429

Returns:

430

Tuple of (lowest_note, highest_note)

431

"""

432

433

def get_note_names(self) -> List[str]:

434

"""

435

Get all note names in bar.

436

437

Returns:

438

List of note names

439

"""

440

```

441

442

### Track Class

443

444

Represents a musical track containing a sequence of bars, typically for a single instrument or voice.

445

446

```python { .api }

447

class Track:

448

"""Musical track containing sequence of bars."""

449

450

def __init__(self, instrument: Any = None):

451

"""

452

Create Track object.

453

454

Parameters:

455

- instrument: Associated instrument object

456

"""

457

458

@property

459

def instrument(self) -> Any:

460

"""Associated instrument."""

461

462

@property

463

def name(self) -> str:

464

"""Track name."""

465

466

def add_bar(self, bar: Bar) -> None:

467

"""

468

Add bar to track.

469

470

Parameters:

471

- bar: Bar object to add

472

"""

473

474

def add_notes(self, note: Union[str, Note, NoteContainer], duration: int = None) -> None:

475

"""

476

Add notes with duration to track.

477

478

Parameters:

479

- note: Notes to add

480

- duration: Note duration

481

"""

482

483

def get_notes(self) -> List[Note]:

484

"""

485

Get all notes in track.

486

487

Returns:

488

List of all Note objects in track

489

"""

490

491

def from_chords(self, chords: List[str], duration: int = 1) -> None:

492

"""

493

Create track from chord list.

494

495

Parameters:

496

- chords: List of chord shorthands

497

- duration: Duration for each chord

498

"""

499

500

def transpose(self, interval: str, up: bool = True) -> None:

501

"""

502

Transpose entire track.

503

504

Parameters:

505

- interval: Interval to transpose

506

- up: Direction (True for up, False for down)

507

"""

508

509

def augment(self) -> None:

510

"""Augment all notes in track."""

511

512

def diminish(self) -> None:

513

"""Diminish all notes in track."""

514

515

def get_tuning(self) -> Any:

516

"""

517

Get instrument tuning.

518

519

Returns:

520

Tuning object if instrument has tuning

521

"""

522

523

def set_tuning(self, tuning: Any) -> None:

524

"""

525

Set instrument tuning.

526

527

Parameters:

528

- tuning: Tuning object

529

"""

530

531

def test_integrity(self) -> bool:

532

"""

533

Test track integrity.

534

535

Returns:

536

True if track structure is valid

537

"""

538

```

539

540

### Composition Class

541

542

Represents a complete musical composition containing multiple tracks with metadata.

543

544

```python { .api }

545

class Composition:

546

"""Complete musical composition with multiple tracks."""

547

548

def __init__(self):

549

"""Create Composition object."""

550

551

@property

552

def title(self) -> str:

553

"""Composition title."""

554

555

@property

556

def subtitle(self) -> str:

557

"""Composition subtitle."""

558

559

@property

560

def author(self) -> str:

561

"""Author name."""

562

563

@property

564

def email(self) -> str:

565

"""Author email."""

566

567

def empty(self) -> None:

568

"""Empty composition of all tracks."""

569

570

def reset(self) -> None:

571

"""Reset composition to initial state."""

572

573

def add_track(self, track: Track) -> None:

574

"""

575

Add track to composition.

576

577

Parameters:

578

- track: Track object to add

579

"""

580

581

def add_note(self, note: Union[str, Note]) -> None:

582

"""

583

Add note to first track.

584

585

Parameters:

586

- note: Note to add

587

"""

588

589

def set_title(self, title: str = "Untitled", subtitle: str = "") -> None:

590

"""

591

Set composition title and subtitle.

592

593

Parameters:

594

- title: Main title

595

- subtitle: Subtitle

596

"""

597

598

def set_author(self, author: str = "", email: str = "") -> None:

599

"""

600

Set author information.

601

602

Parameters:

603

- author: Author name

604

- email: Author email

605

"""

606

```

607

608

### Suite Class

609

610

Represents a suite containing multiple compositions.

611

612

```python { .api }

613

class Suite:

614

"""Suite containing multiple compositions."""

615

616

def __init__(self):

617

"""Create Suite object."""

618

619

def add_composition(self, composition: Composition) -> None:

620

"""

621

Add composition to suite.

622

623

Parameters:

624

- composition: Composition object to add

625

"""

626

627

def set_author(self, author: str, email: str = "") -> None:

628

"""

629

Set author information.

630

631

Parameters:

632

- author: Author name

633

- email: Author email

634

"""

635

636

def set_title(self, title: str, subtitle: str = "") -> None:

637

"""

638

Set suite title and subtitle.

639

640

Parameters:

641

- title: Main title

642

- subtitle: Subtitle

643

"""

644

```

645

646

### Instrument Classes

647

648

Classes representing various musical instruments with range validation and specific capabilities.

649

650

```python { .api }

651

class Instrument:

652

"""Base instrument class."""

653

654

def __init__(self):

655

"""Create Instrument object."""

656

657

def set_range(self, range: Tuple[Note, Note]) -> None:

658

"""

659

Set instrument range.

660

661

Parameters:

662

- range: Tuple of (lowest_note, highest_note)

663

"""

664

665

def note_in_range(self, note: Note) -> bool:

666

"""

667

Check if note is in instrument range.

668

669

Parameters:

670

- note: Note to check

671

672

Returns:

673

True if note is in range

674

"""

675

676

def notes_in_range(self, notes: List[Note]) -> bool:

677

"""

678

Check if all notes are in range.

679

680

Parameters:

681

- notes: List of notes to check

682

683

Returns:

684

True if all notes are in range

685

"""

686

687

def can_play_notes(self, notes: List[Note]) -> bool:

688

"""

689

Check if instrument can play notes.

690

691

Parameters:

692

- notes: List of notes to check

693

694

Returns:

695

True if instrument can play all notes

696

"""

697

698

class Piano(Instrument):

699

"""Piano instrument with 88-key range."""

700

701

def __init__(self):

702

"""Create Piano object with standard range."""

703

704

class Guitar(Instrument):

705

"""Guitar instrument with standard tuning."""

706

707

def __init__(self):

708

"""Create Guitar object with standard tuning."""

709

710

class MidiInstrument(Instrument):

711

"""Generic MIDI instrument."""

712

713

def __init__(self, name: str = ""):

714

"""

715

Create MIDI instrument.

716

717

Parameters:

718

- name: Instrument name

719

"""

720

721

class MidiPercussionInstrument(MidiInstrument):

722

"""MIDI percussion instrument with drum methods."""

723

724

def __init__(self):

725

"""Create MIDI percussion instrument."""

726

727

def acoustic_bass_drum(self) -> Note:

728

"""Return acoustic bass drum note."""

729

730

def snare(self) -> Note:

731

"""Return snare drum note."""

732

733

def hi_hat(self) -> Note:

734

"""Return hi-hat note."""

735

736

def crash_cymbal(self) -> Note:

737

"""Return crash cymbal note."""

738

739

def ride_cymbal(self) -> Note:

740

"""Return ride cymbal note."""

741

742

def open_hi_hat(self) -> Note:

743

"""Return open hi-hat note."""

744

745

def closed_hi_hat(self) -> Note:

746

"""Return closed hi-hat note."""

747

748

# Additional percussion methods available...

749

```

750

751

## Usage Examples

752

753

### Creating and Manipulating Notes

754

755

```python

756

from mingus.containers import Note

757

758

# Create notes

759

note1 = Note("C", 4) # Middle C

760

note2 = Note("F#", 5, velocity=80, channel=1)

761

762

# Manipulate notes

763

note1.transpose("5") # Transpose up a fifth to G

764

note1.octave_up() # Move to octave 5

765

766

# Convert to frequency

767

freq = note1.to_hertz() # Get frequency in Hz

768

print(f"G5 frequency: {freq} Hz")

769

```

770

771

### Working with Chords

772

773

```python

774

from mingus.containers import NoteContainer

775

776

# Create chord from shorthand

777

chord = NoteContainer()

778

chord.from_chord("CM7") # C major 7th chord

779

780

# Analyze chord

781

chord_name = chord.determine() # Returns chord name

782

print(f"Chord: {chord_name}")

783

784

# Manipulate chord

785

chord.transpose("2") # Transpose up a whole step

786

chord.sort() # Sort notes by pitch

787

```

788

789

### Building Musical Structures

790

791

```python

792

from mingus.containers import Bar, Track, Composition

793

794

# Create a bar with notes

795

bar = Bar("C", (4, 4)) # 4/4 time in C major

796

bar.place_notes("C", 4) # Quarter note C

797

bar.place_notes(["E", "G"], 4) # Quarter note E and G together

798

bar.place_rest(2) # Half rest

799

800

# Create track and composition

801

track = Track()

802

track.add_bar(bar)

803

804

composition = Composition()

805

composition.add_track(track)

806

composition.set_title("Simple Melody")

807

```