parse static method

FaustSequencer parse(
  1. String input
)

Implementation

static FaustSequencer parse(String input) {
  final lines = input.trim().split('\n');
  double baseFreq = 261.63; // Default C4
  double bpm = 120.0;
  int grid = 4;
  String patternStr = "";

  // Parse Header
  for (var line in lines) {
    if (line.contains(':')) {
      final parts = line.split(':');
      final key = parts[0].trim().toLowerCase();
      final val = parts[1].trim();
      if (key == 'basefreq') baseFreq = double.tryParse(val) ?? baseFreq;
      if (key == 'bpm') bpm = double.tryParse(val) ?? bpm;
      if (key == 'grid') grid = int.tryParse(val) ?? grid;
    } else if (line.trim().isNotEmpty) {
      patternStr += " ${line.trim()}";
    }
  }

  final sequencer = FaustSequencer(tempoBpm: bpm);
  final double stepDuration = 1.0 / grid;
  final List<String> blocks = patternStr.trim().split(RegExp(r'\s+'));

  // State tracking for each instrument
  final Map<int, double> lastFreq = {};

  for (int i = 0; i < blocks.length; i++) {
    final String block = blocks[i];
    final double currentBeat = i * stepDuration;

    if (block == '.') {
      // Continuity: Handled by extending duration in the addNote call later or just skipping
      continue;
    } else if (block == '^') {
      // Meend: Look ahead for target note
      continue;
    } else if (block == ' ') {
      // Stop is implicit if no note is played, but we can send a 0-velocity event
      continue;
    }

    // Try to parse InstrumentID + Shruti (e.g., 12Sa, 1Pa)
    final match = RegExp(r'^(\d+)([a-zA-Z12]+)$').firstMatch(block);
    if (match != null) {
      final int instId = int.parse(match.group(1)!);
      String shruti = match.group(2)!;

      // Correct Pa if lowercase pa was used
      if (shruti == "pa") shruti = "Pa";
      if (shruti == "sa") shruti = "Sa";

      if (_ratios.containsKey(shruti)) {
        final double freq = baseFreq * _ratios[shruti]!;

        // Determine duration by looking ahead for '.'
        double duration = stepDuration;
        int lookAhead = i + 1;
        while (lookAhead < blocks.length && blocks[lookAhead] == '.') {
          duration += stepDuration;
          lookAhead++;
        }

        // Check if previous block was Meend '^'
        if (i > 0 && blocks[i-1] == '^' && lastFreq.containsKey(instId)) {
           // Generate a sweep from lastFreq[instId] to freq
           _generateMeend(sequencer, instId, lastFreq[instId]!, freq, currentBeat - stepDuration, stepDuration);
        }

        sequencer.addNote(
          instrumentId: instId,
          pitch: freq,
          beat: currentBeat,
          duration: duration * 0.95,
          velocity: 0.8,
          legato: lookAhead < blocks.length && blocks[lookAhead] == '^',
        );

        lastFreq[instId] = freq;
      }
    }
  }

  return sequencer;
}