parse static method
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;
}