flutter_music_notation 0.1.0 copy "flutter_music_notation: ^0.1.0" to clipboard
flutter_music_notation: ^0.1.0 copied to clipboard

A professional music notation rendering library for Flutter with MIDI support and synchronized playback.

example/lib/main.dart

// example/lib/main.dart - Comprehensive Phase 3 Demo

import 'package:flutter/material.dart';
import 'package:flutter_music_notation/flutter_music_notation.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Music Notation - Phase 3 Complete',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const ComprehensiveDemo(),
    );
  }
}

class ComprehensiveDemo extends StatefulWidget {
  const ComprehensiveDemo({super.key});

  @override
  State<ComprehensiveDemo> createState() => _ComprehensiveDemoState();
}

class _ComprehensiveDemoState extends State<ComprehensiveDemo> {
  int _selectedTab = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Flutter Music Notation - Complete Demo'),
      ),
      body: Column(
        children: [
          // Tab selector
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Row(
              children: [
                _buildTabButton('Clefs', 0),
                _buildTabButton('Key Signatures', 1),
                _buildTabButton('Time Signatures', 2),
                _buildTabButton('Notes & Rests', 3),
                _buildTabButton('Dotted Notes', 4),
                _buildTabButton('Ledger Lines', 5),
                _buildTabButton('Barlines', 6),
                _buildTabButton('Complete Pieces', 7),
              ],
            ),
          ),
          const Divider(height: 1),
          // Content
          Expanded(
            child: SingleChildScrollView(
              child: _buildTabContent(),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildTabButton(String label, int index) {
    final isSelected = _selectedTab == index;
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ElevatedButton(
        onPressed: () => setState(() => _selectedTab = index),
        style: ElevatedButton.styleFrom(
          backgroundColor: isSelected ? Colors.blue : Colors.grey[300],
          foregroundColor: isSelected ? Colors.white : Colors.black,
        ),
        child: Text(label),
      ),
    );
  }

  Widget _buildTabContent() {
    switch (_selectedTab) {
      case 0:
        return _buildClefsDemo();
      case 1:
        return _buildKeySignaturesDemo();
      case 2:
        return _buildTimeSignaturesDemo();
      case 3:
        return _buildNotesAndRestsDemo();
      case 4:
        return _buildDottedNotesDemo();
      case 5:
        return _buildLedgerLinesDemo();
      case 6:
        return _buildBarlinesDemo();
      case 7:
        return _buildCompletePiecesDemo();
      default:
        return const SizedBox();
    }
  }

  // ========== TAB 1: CLEFS ==========
  Widget _buildClefsDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('All Clef Types'),

        _buildSection(
          'Treble Clef (G Clef)',
          _createMeasuresForClef(ClefType.treble),
          clef: ClefType.treble,
        ),

        _buildSection(
          'Bass Clef (F Clef)',
          _createMeasuresForClef(ClefType.bass),
          clef: ClefType.bass,
        ),

        _buildSection(
          'Alto Clef (C Clef on Middle Line)',
          _createMeasuresForClef(ClefType.alto),
          clef: ClefType.alto,
        ),

        _buildSection(
          'Tenor Clef (C Clef on 4th Line)',
          _createMeasuresForClef(ClefType.tenor),
          clef: ClefType.tenor,
        ),
      ],
    );
  }

  List<Measure> _createMeasuresForClef(ClefType clef) {
    // Create scale appropriate for each clef
    final notes = switch (clef) {
      ClefType.treble => [
        Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
        Note(pitch: Pitch(noteName: NoteName.D, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
        Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
        Note(pitch: Pitch(noteName: NoteName.F, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
      ],
      ClefType.bass => [
        Note(pitch: Pitch(noteName: NoteName.E, octave: 2), duration: const NoteDuration.quarter(), startBeat: 0.0),
        Note(pitch: Pitch(noteName: NoteName.F, octave: 2), duration: const NoteDuration.quarter(), startBeat: 1.0),
        Note(pitch: Pitch(noteName: NoteName.G, octave: 2), duration: const NoteDuration.quarter(), startBeat: 2.0),
        Note(pitch: Pitch(noteName: NoteName.A, octave: 2), duration: const NoteDuration.quarter(), startBeat: 3.0),
      ],
      ClefType.alto => [
        Note(pitch: Pitch(noteName: NoteName.C, octave: 3), duration: const NoteDuration.quarter(), startBeat: 0.0),
        Note(pitch: Pitch(noteName: NoteName.D, octave: 3), duration: const NoteDuration.quarter(), startBeat: 1.0),
        Note(pitch: Pitch(noteName: NoteName.E, octave: 3), duration: const NoteDuration.quarter(), startBeat: 2.0),
        Note(pitch: Pitch(noteName: NoteName.F, octave: 3), duration: const NoteDuration.quarter(), startBeat: 3.0),
      ],
      ClefType.tenor => [
        Note(pitch: Pitch(noteName: NoteName.A, octave: 2), duration: const NoteDuration.quarter(), startBeat: 0.0),
        Note(pitch: Pitch(noteName: NoteName.B, octave: 2), duration: const NoteDuration.quarter(), startBeat: 1.0),
        Note(pitch: Pitch(noteName: NoteName.C, octave: 3), duration: const NoteDuration.quarter(), startBeat: 2.0),
        Note(pitch: Pitch(noteName: NoteName.D, octave: 3), duration: const NoteDuration.quarter(), startBeat: 3.0),
      ],
    };

    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: notes,
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 2: KEY SIGNATURES ==========
  Widget _buildKeySignaturesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('All Key Signatures'),

        const Padding(
          padding: EdgeInsets.all(16.0),
          child: Text(
            'Sharp Keys (1-7 sharps)',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
        ),

        _buildSection('C Major (0 sharps)', _createKeySignatureMeasure(KeySignature.cMajor)),
        _buildSection('G Major (1 sharp: F♯)', _createKeySignatureMeasure(KeySignature.gMajor)),
        _buildSection('D Major (2 sharps: F♯, C♯)', _createKeySignatureMeasure(KeySignature.dMajor)),
        _buildSection('A Major (3 sharps)', _createKeySignatureMeasure(KeySignature.aMajor)),
        _buildSection('E Major (4 sharps)', _createKeySignatureMeasure(KeySignature.eMajor)),
        _buildSection('B Major (5 sharps)', _createKeySignatureMeasure(KeySignature.bMajor)),
        _buildSection('F♯ Major (6 sharps)', _createKeySignatureMeasure(KeySignature.fSharpMajor)),
        _buildSection('C♯ Major (7 sharps)', _createKeySignatureMeasure(KeySignature.cSharpMajor)),

        const SizedBox(height: 20),
        const Padding(
          padding: EdgeInsets.all(16.0),
          child: Text(
            'Flat Keys (1-7 flats)',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
        ),

        _buildSection('F Major (1 flat: B♭)', _createKeySignatureMeasure(KeySignature.fMajor)),
        _buildSection('B♭ Major (2 flats)', _createKeySignatureMeasure(KeySignature.bFlatMajor)),
        _buildSection('E♭ Major (3 flats)', _createKeySignatureMeasure(KeySignature.eFlatMajor)),
        _buildSection('A♭ Major (4 flats)', _createKeySignatureMeasure(KeySignature.aFlatMajor)),
        _buildSection('D♭ Major (5 flats)', _createKeySignatureMeasure(KeySignature.dFlatMajor)),
        _buildSection('G♭ Major (6 flats)', _createKeySignatureMeasure(KeySignature.gFlatMajor)),
        _buildSection('C♭ Major (7 flats)', _createKeySignatureMeasure(KeySignature.cFlatMajor)),
      ],
    );
  }

  List<Measure> _createKeySignatureMeasure(KeySignature keySignature) {
    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: keySignature,
        notes: [
          Note(
            pitch: Pitch(noteName: NoteName.C, octave: 4),
            duration: const NoteDuration.whole(),
            startBeat: 0.0,
          ),
        ],
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 3: TIME SIGNATURES ==========
  Widget _buildTimeSignaturesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Common Time Signatures'),

        _buildSection('4/4 (Common Time)', _createTimeSignatureMeasure(TimeSignature.fourFour)),
        _buildSection('3/4 (Waltz Time)', _createTimeSignatureMeasure(TimeSignature.threeFour)),
        _buildSection('2/4', _createTimeSignatureMeasure(TimeSignature.twoFour)),
        _buildSection('6/8', _createTimeSignatureMeasure(TimeSignature.sixEight)),
        _buildSection('3/8', _createTimeSignatureMeasure(TimeSignature.threeEight)),
        _buildSection('12/8', _createTimeSignatureMeasure(TimeSignature.twelveEight)),
        _buildSection('2/2 (Cut Time)', _createTimeSignatureMeasure(TimeSignature.twoTwo)),
      ],
    );
  }

  List<Measure> _createTimeSignatureMeasure(TimeSignature timeSignature) {
    // Create notes that fill the measure based on time signature
    final notes = <Note>[];
    final beatsPerMeasure = timeSignature.beatsPerMeasure;

    // Fill with quarter notes (1 beat each in 4/4)
    for (double beat = 0; beat < beatsPerMeasure && notes.length < 4; beat += 1.0) {
      notes.add(
        Note(
          pitch: Pitch(noteName: NoteName.values[notes.length % 7], octave: 4),
          duration: const NoteDuration.quarter(),
          startBeat: beat,
        ),
      );
    }

    return [
      Measure(
        number: 0,
        timeSignature: timeSignature,
        keySignature: KeySignature.cMajor,
        notes: notes,
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 4: NOTES AND RESTS ==========
  Widget _buildNotesAndRestsDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Note Durations and Rests'),

        _buildSection('Whole Notes', _createNoteDurationMeasure(DurationType.whole)),
        _buildSection('Half Notes', _createNoteDurationMeasure(DurationType.half)),
        _buildSection('Quarter Notes', _createNoteDurationMeasure(DurationType.quarter)),
        _buildSection('Eighth Notes', _createNoteDurationMeasure(DurationType.eighth)),
        _buildSection('Sixteenth Notes', _createNoteDurationMeasure(DurationType.sixteenth)),

        const SizedBox(height: 20),
        _buildSection('Mixed Notes and Rests', _createMixedNotesAndRests()),
      ],
    );
  }

  List<Measure> _createNoteDurationMeasure(DurationType durationType) {
    final duration = NoteDuration(type: durationType);
    final notesPerMeasure = (4.0 / duration.beats).floor();

    final notes = <Note>[];
    for (int i = 0; i < notesPerMeasure && i < 8; i++) {
      notes.add(
        Note(
          pitch: Pitch(noteName: NoteName.values[(i + 2) % 7], octave: 4),
          duration: duration,
          startBeat: i * duration.beats,
        ),
      );
    }

    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: notes,
        endBarline: BarlineType.final_,
      ),
    ];
  }

  List<Measure> _createMixedNotesAndRests() {
    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.eighth(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.eighth(), startBeat: 2.5),
        ],
        rests: [
          const Rest(duration: NoteDuration.quarter(), startBeat: 1.0),
          const Rest(duration: NoteDuration.half(), startBeat: 3.0),
        ],
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 5: DOTTED NOTES ==========
  Widget _buildDottedNotesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Dotted Notes'),

        _buildSection('Dotted Half Notes', _createDottedNotesMeasure(DurationType.half, 1)),
        _buildSection('Dotted Quarter Notes', _createDottedNotesMeasure(DurationType.quarter, 1)),
        _buildSection('Dotted Eighth Notes', _createDottedNotesMeasure(DurationType.eighth, 1)),
        _buildSection('Double Dotted Notes', _createDottedNotesMeasure(DurationType.half, 2)),
      ],
    );
  }

  List<Measure> _createDottedNotesMeasure(DurationType durationType, int dots) {
    final duration = NoteDuration(type: durationType, dots: dots);

    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: duration, startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: duration, startBeat: duration.beats),
        ],
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 6: LEDGER LINES ==========
  Widget _buildLedgerLinesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Ledger Lines'),

        _buildSection('Above Staff (Treble)', _createLedgerLinesMeasure(true, ClefType.treble)),
        _buildSection('Below Staff (Treble)', _createLedgerLinesMeasure(false, ClefType.treble)),
        _buildSection('Above Staff (Bass)', _createLedgerLinesMeasure(true, ClefType.bass), clef: ClefType.bass),
        _buildSection('Below Staff (Bass)', _createLedgerLinesMeasure(false, ClefType.bass), clef: ClefType.bass),
      ],
    );
  }

  List<Measure> _createLedgerLinesMeasure(bool above, ClefType clef) {
    final notes = <Note>[];

    if (above) {
      if (clef == ClefType.treble) {
        notes.addAll([
          Note(pitch: Pitch(noteName: NoteName.A, octave: 5), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.C, octave: 6), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 6), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 6), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ]);
      } else {
        notes.addAll([
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.B, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ]);
      }
    } else {
      if (clef == ClefType.treble) {
        notes.addAll([
          Note(pitch: Pitch(noteName: NoteName.C, octave: 3), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.A, octave: 2), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.F, octave: 2), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.D, octave: 2), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ]);
      } else {
        notes.addAll([
          Note(pitch: Pitch(noteName: NoteName.E, octave: 1), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.C, octave: 1), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.A, octave: 0), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.F, octave: 0), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ]);
      }
    }

    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: notes,
        endBarline: BarlineType.final_,
      ),
    ];
  }

  // ========== TAB 7: BARLINES ==========
  Widget _buildBarlinesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Barline Types'),

        _buildSection('Single Barline', _createBarlineMeasures([BarlineType.single])),
        _buildSection('Double Barline', _createBarlineMeasures([BarlineType.double_])),
        _buildSection('Final Barline', _createBarlineMeasures([BarlineType.final_])),
        _buildSection('Multiple Measures', _createBarlineMeasures([
          BarlineType.single,
          BarlineType.double_,
          BarlineType.final_,
        ])),
      ],
    );
  }

  List<Measure> _createBarlineMeasures(List<BarlineType> barlineTypes) {
    final measures = <Measure>[];

    for (int i = 0; i < barlineTypes.length; i++) {
      measures.add(
        Measure(
          number: i,
          timeSignature: TimeSignature.fourFour,
          keySignature: KeySignature.cMajor,
          notes: [
            Note(
              pitch: Pitch(noteName: NoteName.values[(i + 2) % 7], octave: 4),
              duration: const NoteDuration.whole(),
              startBeat: 0.0,
            ),
          ],
          endBarline: barlineTypes[i],
        ),
      );
    }

    return measures;
  }

  // ========== TAB 8: COMPLETE PIECES ==========
  Widget _buildCompletePiecesDemo() {
    return Column(
      children: [
        const SizedBox(height: 20),
        _buildDemoTitle('Complete Musical Pieces'),

        _buildSection('Ode to Joy (Theme)', _createOdeToJoy()),
        _buildSection('Mary Had a Little Lamb', _createMaryHadALittleLamb()),
        _buildSection('Twinkle Twinkle Little Star', _createTwinkleTwinkle()),
      ],
    );
  }

  List<Measure> _createOdeToJoy() {
    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.F, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ],
        endBarline: BarlineType.single,
      ),
      Measure(
        number: 1,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.F, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.D, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ],
        endBarline: BarlineType.double_,
      ),
    ];
  }

  List<Measure> _createMaryHadALittleLamb() {
    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.D, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.D, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ],
        endBarline: BarlineType.single,
      ),
      Measure(
        number: 1,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.E, octave: 4), duration: const NoteDuration.half(), startBeat: 2.0),
        ],
        endBarline: BarlineType.final_,
      ),
    ];
  }

  List<Measure> _createTwinkleTwinkle() {
    return [
      Measure(
        number: 0,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.C, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.quarter(), startBeat: 2.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.quarter(), startBeat: 3.0),
        ],
        endBarline: BarlineType.single,
      ),
      Measure(
        number: 1,
        timeSignature: TimeSignature.fourFour,
        keySignature: KeySignature.cMajor,
        notes: [
          Note(pitch: Pitch(noteName: NoteName.A, octave: 4), duration: const NoteDuration.quarter(), startBeat: 0.0),
          Note(pitch: Pitch(noteName: NoteName.A, octave: 4), duration: const NoteDuration.quarter(), startBeat: 1.0),
          Note(pitch: Pitch(noteName: NoteName.G, octave: 4), duration: const NoteDuration.half(), startBeat: 2.0),
        ],
        endBarline: BarlineType.double_,
      ),
    ];
  }

  // ========== HELPER METHODS ==========
  Widget _buildDemoTitle(String title) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: Text(
        title,
        style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      ),
    );
  }

  Widget _buildSection(
      String title,
      List<Measure> measures, {
        ClefType clef = ClefType.treble,
        double height = 180,
      }) {
    return Column(
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
          child: Text(
            title,
            style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
          ),
        ),
        Container(
          height: height,
          margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey),
            color: Colors.white,
            borderRadius: BorderRadius.circular(8),
          ),
          child: NotationView(
            measures: measures,
            config: NotationConfig(
              staffSpaceSize: 12,
              noteWidth: 50,
              leftMargin: 0,
              measureSpacing: 30,
              clef: clef,
              width: _calculateStaffWidth(measures, NotationConfig()),
            ),
          ),
        ),
      ],
    );
  }

  double _calculateStaffWidth(List<Measure> measures, NotationConfig config) {
    // Estimate number of note/rest "slots" per measure
    int totalSlots = measures.fold(0, (sum, m) {
      int noteCount = m.notes.length;
      int restCount = m.rests.length;
      return sum + noteCount + restCount;
    });

    // Left margin + note widths + spacing between measures
    return config.leftMargin +
        (totalSlots * config.noteWidth) +
        ((measures.length - 1) * config.measureSpacing) +
        200; // right padding buffer
  }

}
1
likes
150
points
24
downloads

Publisher

verified publisherempyrealworks.com

Weekly Downloads

A professional music notation rendering library for Flutter with MIDI support and synchronized playback.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on flutter_music_notation