Skip to content

Commit

Permalink
Implement opening/closing files + voice adding/removing/etc
Browse files Browse the repository at this point in the history
  • Loading branch information
SwadicalRag committed Jan 3, 2021
1 parent ab995b0 commit 3335dbd
Show file tree
Hide file tree
Showing 5 changed files with 551 additions and 113 deletions.
27 changes: 21 additions & 6 deletions lib/controllers/muonproject.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:path/path.dart' as p;

class MuonProjectController extends GetxController {
final projectDir = "".obs;
final projectFileName = "project.json".obs;
String get projectFileNameNoExt => p.basenameWithoutExtension(projectFileName.value);

// tempo
final bpm = 120.0.obs;
Expand All @@ -21,10 +23,13 @@ class MuonProjectController extends GetxController {
final voices = RxList<MuonVoiceController>([]);

// other
final currentVoiceID = 0.obs;
final selectedNotes = Map<MuonNoteController,bool>().obs;
final playheadTime = 0.0.obs;
List<MuonNote> copiedNotes = [];
List<MuonVoiceController> copiedNotesVoices = [];
final internalStatus = "idle".obs;
int internalPlayTime = 0;

// subdivision manager
final currentSubdivision = 1.obs;
Expand All @@ -44,6 +49,10 @@ class MuonProjectController extends GetxController {
currentSubdivision.value = subdivision;
}

int getLabelMillisecondOffset() {
return (this.beatsPerMeasure / (this.bpm.value / 60) * 1000).round();
}

void updateWith(MuonProjectController controller) {
this.projectDir.value = controller.projectDir.value;
this.bpm.value = controller.bpm.value;
Expand All @@ -67,7 +76,6 @@ class MuonProjectController extends GetxController {
out.projectDir.value = "startup";

final baseVoice = MuonVoiceController();
baseVoice.modelName.value = "KIRITAN";
baseVoice.addNote(
MuonNoteController()
..startAtTime.value = 0
Expand Down Expand Up @@ -163,7 +171,6 @@ class MuonProjectController extends GetxController {

if(midi.header.format == 0) {
var voice = MuonVoiceController()..project = this;
voice.modelName.value = "KIRITAN";

int timeUnitMulFactor = 1;
if(this.timeUnitsPerBeat.value != midi.header.ticksPerBeat) {
Expand Down Expand Up @@ -255,7 +262,6 @@ class MuonProjectController extends GetxController {

void importVoiceFromMusicXML(MusicXML musicXML,bool importTimeMetadata) {
var voice = MuonVoiceController()..project = this;
voice.modelName.value = "KIRITAN";

int timeUnitMulFactor = 1;
for(final event in musicXML.events) {
Expand Down Expand Up @@ -312,6 +318,7 @@ class MuonProjectController extends GetxController {

voice.sortNotesByTime();

musicXML.rest((this.beatsPerMeasure.value * divEvent.divisions).toDouble(),1);
var lastNoteEndTime = 0;
for(final note in voice.notes) {
if(note.startAtTime > lastNoteEndTime) {
Expand All @@ -333,6 +340,7 @@ class MuonProjectController extends GetxController {

lastNoteEndTime = note.startAtTime.value + note.duration.value;
}
musicXML.rest((this.beatsPerMeasure.value * divEvent.divisions).toDouble(),1);

return musicXML;
}
Expand All @@ -342,14 +350,20 @@ class MuonProjectController extends GetxController {
serializable.save();
}

static MuonProjectController loadFromDir(String projectDir) {
final serializable = MuonProject.loadFromDir(projectDir);
static MuonProjectController loadFromDir(String projectDir,String projectFileName) {
final serializable = MuonProject.loadFromDir(projectDir,projectFileName);
return MuonProjectController.fromSerializable(serializable);
}

static MuonProjectController loadFromFile(String projectFile) {
final serializable = MuonProject.loadFromFile(projectFile);
return MuonProjectController.fromSerializable(serializable);
}

MuonProject toSerializable() {
final out = MuonProject();
out.projectDir = this.projectDir.value;
out.projectFileName = this.projectFileName.value;
out.bpm = this.bpm.value;
out.timeUnitsPerBeat = this.timeUnitsPerBeat.value;
out.beatsPerMeasure = this.beatsPerMeasure.value;
Expand All @@ -363,6 +377,7 @@ class MuonProjectController extends GetxController {
static MuonProjectController fromSerializable(MuonProject obj) {
final out = MuonProjectController();
out.projectDir.value = obj.projectDir;
out.projectFileName.value = obj.projectFileName;
out.bpm.value = obj.bpm;
out.timeUnitsPerBeat.value = obj.timeUnitsPerBeat;
out.beatsPerMeasure.value = obj.beatsPerMeasure;
Expand All @@ -385,7 +400,7 @@ void testProject() {

originalProject.save();

final loadedProject = MuonProjectController.loadFromDir("testproject");
final loadedProject = MuonProjectController.loadFromDir("testproject","project.json");
final voiceMusicXML = loadedProject.voices[0].exportVoiceToMusicXML();

final serializedMusicXML = serializeMusicXML(voiceMusicXML);
Expand Down
88 changes: 65 additions & 23 deletions lib/controllers/muonvoice.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:muon/controllers/muonnote.dart';
import 'package:muon/controllers/muonproject.dart';
import 'package:muon/serializable/muon.dart';
import 'package:muon/serializable/settings.dart';
import 'package:muon/logic/musicxml.dart';
import 'package:flutter_audio_desktop/flutter_audio_desktop.dart';
import 'package:path/path.dart' as p;

String getRawProgramPath(String programName) {
return getMuonSettings().neutrinoDir + "/" + programName;
Expand All @@ -22,11 +24,35 @@ String getProgramPath(String programName) {
return out;
}

List<String> getAllVoiceModels() {
final List<String> items = [];

final modelsDir = Directory(getRawProgramPath("model"));
final modelsDirFiles = modelsDir.listSync();

for(final modelsDirFile in modelsDirFiles) {
if(modelsDirFile is Directory) {
final modelName = p.relative(modelsDirFile.path,from: modelsDir.path);
items.add(modelName);
}
}

items.sort();

return items;
}

String getDefaultVoiceModel() {
final models = getAllVoiceModels();
if(models.length == 0) {return "";}
return models[0];
}

class MuonVoiceController extends GetxController {
MuonProjectController project;

// voice metadata
final modelName = "".obs;
final modelName = getDefaultVoiceModel().obs;
final randomiseTiming = false.obs;

// notes
Expand All @@ -45,6 +71,22 @@ class MuonVoiceController extends GetxController {
notes.add(note);
}

static final noteColors = [
Colors.blue,
Colors.purple,
Colors.amber,
Colors.indigo,
Colors.green,
Colors.teal,
Colors.brown,
];
get color {
final voiceID = (project != null ? project.voices.indexOf(this) : -1) + 1;
return noteColors[voiceID % noteColors.length];
}

String get voiceFileName => project.projectFileNameNoExt + "_" + project.voices.indexOf(this).toString() + "_voice";

Future<void> makeLabels() async {
final musicXML = exportVoiceToMusicXML();
final musicXMLString = serializeMusicXML(musicXML);
Expand All @@ -65,15 +107,15 @@ class MuonVoiceController extends GetxController {
Directory(project.getProjectFilePath("label/mono/")).createSync();
}

final musicXMLPath = project.getProjectFilePath("musicxml/" + project.voices.indexOf(this).toString() + "_voice.musicxml");
final musicXMLPath = project.getProjectFilePath("musicxml/" + voiceFileName + ".musicxml");

File(musicXMLPath)
.writeAsStringSync(musicXMLString);

await Process.run(getProgramPath("musicXMLtoLabel"), [
musicXMLPath,
project.getProjectFilePath("label/full/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("label/mono/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("label/full/" + voiceFileName + ".lab"),
project.getProjectFilePath("label/mono/" + voiceFileName + ".lab"),
"-x",
getRawProgramPath("settings/dic"),
]).then((ProcessResult results) {
Expand All @@ -86,13 +128,13 @@ class MuonVoiceController extends GetxController {
Directory(project.getProjectFilePath("neutrino/")).createSync();
}

print(getRawProgramPath("model/" + (modelName.value ?? "KIRITAN") + "/"));
print(getRawProgramPath("model/" + (modelName.value) + "/"));
await Process.run(getProgramPath("NEUTRINO"), [
project.getProjectFilePath("label/full/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("label/timing/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.f0"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.mgc"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.bap"),
project.getProjectFilePath("label/full/" + voiceFileName + ".lab"),
project.getProjectFilePath("label/timing/" + voiceFileName + ".lab"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".f0"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".mgc"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".bap"),
getRawProgramPath("model/" + modelName.value + "/"),
"-n","8",
"-k","0",
Expand All @@ -108,14 +150,14 @@ class MuonVoiceController extends GetxController {
Directory(project.getProjectFilePath("audio/")).createSync();
}

print(getRawProgramPath("model/" + (modelName.value ?? "KIRITAN") + "/"));
print(getRawProgramPath("model/" + (modelName.value) + "/"));
await Process.run(getProgramPath("WORLD"), [
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.f0"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.mgc"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.bap"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".f0"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".mgc"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".bap"),
"-f","1.0",
"-m","1.0",
"-o",project.getProjectFilePath("audio/" + project.voices.indexOf(this).toString() + "_voice_world.wav"),
"-o",project.getProjectFilePath("audio/" + voiceFileName + "_world.wav"),
"-n","8",
"-t",
]).then((ProcessResult results) {
Expand All @@ -128,15 +170,15 @@ class MuonVoiceController extends GetxController {
Directory(project.getProjectFilePath("audio/")).createSync();
}

print(getRawProgramPath("model/" + (modelName.value ?? "KIRITAN") + "/"));
print(getRawProgramPath("model/" + (modelName.value) + "/"));
await Process.run(getProgramPath("NSF_IO"), [
project.getProjectFilePath("label/full/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("label/timing/" + project.voices.indexOf(this).toString() + "_voice.lab"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.f0"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.mgc"),
project.getProjectFilePath("neutrino/" + project.voices.indexOf(this).toString() + "_voice.bap"),
project.getProjectFilePath("label/full/" + voiceFileName + ".lab"),
project.getProjectFilePath("label/timing/" + voiceFileName + ".lab"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".f0"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".mgc"),
project.getProjectFilePath("neutrino/" + voiceFileName + ".bap"),
modelName.value,
project.getProjectFilePath("audio/" + project.voices.indexOf(this).toString() + "_voice_nsf.wav"),
project.getProjectFilePath("audio/" + voiceFileName + "_nsf.wav"),
"-t",
],workingDirectory: getRawProgramPath("")).then((ProcessResult results) {
print(results.stdout);
Expand All @@ -152,7 +194,7 @@ class MuonVoiceController extends GetxController {
}

await audioPlayer.unload();
final suc = await audioPlayer.load(project.getProjectFilePath("audio/" + voiceID.toString() + "_voice_world.wav"));
final suc = await audioPlayer.load(project.getProjectFilePath("audio/" + voiceFileName + "_world.wav"));

audioPlayerDuration = (await audioPlayer.getDuration()).inMilliseconds;
audioPlayer.setPosition(playPos ?? Duration(seconds: 2));
Expand Down
Loading

0 comments on commit 3335dbd

Please sign in to comment.