diff options
Diffstat (limited to 'lib/utils')
| -rw-r--r-- | lib/utils/esense_input.dart | 20 | ||||
| -rw-r--r-- | lib/utils/simfile.dart | 23 | 
2 files changed, 36 insertions, 7 deletions
| diff --git a/lib/utils/esense_input.dart b/lib/utils/esense_input.dart index b738664..14cf7de 100644 --- a/lib/utils/esense_input.dart +++ b/lib/utils/esense_input.dart @@ -8,9 +8,12 @@ import 'package:sense_the_rhythm/models/arrow_direction.dart';  import 'package:sense_the_rhythm/models/input_direction.dart';  class ESenseInput { +  // create singleton that is available on all widgets so it does not have to be +  // carried down in the widget tree    static final instance = ESenseInput._();    ESenseManager eSenseManager = ESenseManager('unknown'); +  // valuenotifier allows widgets to rerender when the value changes    ValueNotifier<String> deviceStatus = ValueNotifier('Disconnected');    StreamSubscription? subscription; @@ -29,8 +32,11 @@ class ESenseInput {      _listenToESense();    } +  /// ask and check if permissions are enabled and granted    Future<bool> _askForPermissions() async { +    // is desktop      if (!Platform.isAndroid && !Platform.isIOS) return false; +    // is bluetooth even enabled?      if (!await Permission.bluetooth.serviceStatus.isEnabled) {        deviceStatus.value = "Bluetooth is disabled!";        return false; @@ -55,6 +61,7 @@ class ESenseInput {      return true;    } +  /// listen to connectionEvents and set deviceStatus    void _listenToESense() {      // if you want to get the connection events when connecting,      // set up the listener BEFORE connecting... @@ -89,12 +96,14 @@ class ESenseInput {      });    } +  /// get eSenseEvent stream only containung button events    Stream<ButtonEventChanged> buttonEvents() {      return eSenseManager.eSenseEvents          .where((event) => event.runtimeType == ButtonEventChanged)          .cast();    } +  /// sets sampling rate and listens to sensorEvents    void _startListenToSensorEvents() async {      // // any changes to the sampling frequency must be done BEFORE listening to sensor events      print('setting sampling frequency...'); @@ -115,11 +124,14 @@ class ESenseInput {      sampling = true;    } +  /// cancels the sensorEvents listening    void _pauseListenToSensorEvents() async {      subscription?.cancel();      sampling = false;    } +  /// add up all new gyro [data] in the form of deg/s multiplied by scaling factor +  /// to get real angles    void _parseGyroData(List<int> data) {      // Float value in deg/s = Gyro value / Gyro scale factor      // The default configuration is +- 500deg/s for the gyroscope. @@ -131,6 +143,7 @@ class ESenseInput {      // print('${z.toDouble() / 500.0 * (1.0 / 10.0)}');    } +  /// nulls all angles and reset inputDirection    void resetAngles() {      inputDirection.reset();      x = 0; @@ -138,26 +151,29 @@ class ESenseInput {      z = 0;    } +  /// get InputDirection by checking if angels are in defined ranges and +  /// calibrating based on the [expect]ed direction from ArrowDirection    InputDirection getInputDirection(ArrowDirection expect) { +    // check if angle is in range      inputDirection.up = z > 180 && z < 340;      inputDirection.down = z > 20 && z < 180;      inputDirection.left = y > 0 && y < 180;      inputDirection.right = y > 180 && y < 360; +    // calibrate based on expected directoin from ArrowDirection      if (expect == ArrowDirection.up && inputDirection.up ||          expect == ArrowDirection.down && inputDirection.down) {        y = 0; -      print("ehit");      }      if (expect == ArrowDirection.left && inputDirection.left ||          expect == ArrowDirection.right && inputDirection.right) {        z = 0; -      print("ehit");      }      return inputDirection;    } +  /// connect to ESense with [deviceName] by first asking for permissions    Future<void> connectToESense(String deviceName) async {      if (!connected) {        bool permissionSuccessfull = await _askForPermissions(); diff --git a/lib/utils/simfile.dart b/lib/utils/simfile.dart index c528084..71613a9 100644 --- a/lib/utils/simfile.dart +++ b/lib/utils/simfile.dart @@ -55,6 +55,7 @@ class Simfile {    Simfile(this.simfilePath); +  /// parses a chart tag with metadata [keys] and note data [value]    void _parseChart({required List<String> keys, required String value}) {      Chart chart = Chart();      chart.chartType = keys[1]; @@ -63,6 +64,7 @@ class Simfile {      chart.numericalMeter = int.parse(keys[4]);      chart.radarValues = keys[5]; +    // find simplest chart      if (chartSimplest == null ||          (chart.difficulty!.index <= chartSimplest!.difficulty!.index &&              chart.numericalMeter! <= chartSimplest!.numericalMeter!)) { @@ -78,8 +80,10 @@ class Simfile {          measures.add(measure);        } +      // for now only use the first bpm value        double bpm = bpms.entries.first.value; +      // calculate timing for all notes based on offset, bpm and measure        for (final (measureIndex, measure) in measures.indexed) {          for (final (noteIndex, noteData) in measure.indexed) {            double beat = measureIndex * 4.0 + @@ -95,10 +99,13 @@ class Simfile {      }    } +  /// parse a tag based on a regex match [fieldData] and parsing the value based +  /// on the key    void _parseTag(RegExpMatch fieldData) {      List<String> keys =          fieldData[1]!.split(':').map((key) => key.trim()).toList();      String value = fieldData[2]!; +      if (keys[0] == "BPMS") {        for (final pairRaw in value.split(',')) {          List<String> pair = pairRaw.split('='); @@ -122,14 +129,18 @@ class Simfile {      _parseChart(keys: keys, value: value);    } +  /// load the simfile    Future<bool> load() async {      directoryPath = File(simfilePath).parent.path;      lines = File(simfilePath).readAsStringSync(); +    // remove comments      RegExp commentsRegExp = RegExp(r'//.*$');      lines = lines?.replaceAll(commentsRegExp, ''); +    // find all tags      RegExp fieldDataRegExp = RegExp(r'#([^;]+):([^;]*);'); +    // parse all tags      for (final fieldData in fieldDataRegExp.allMatches(lines!)) {        try {          _parseTag(fieldData); @@ -138,11 +149,8 @@ class Simfile {        }      } -    String? musicFileName = tags["MUSIC"]; -    if (musicFileName == null) return false; -    String? bannerFileName = tags["BANNER"]; -    if (bannerFileName == null) return false; - +    // searching for audio and banned in the directory is more robust than using +    // values from metadata as they are wrong more often      for (FileSystemEntity entity in Directory(directoryPath!).listSync()) {        if (entity.path.endsWith('.ogg')) {          audioPath = entity.path; @@ -152,6 +160,11 @@ class Simfile {        }      } +    // dont use this simfile of files are missing +    if (audioPath == null) return false; +    if (bannerPath == null) return false; + +    // get duration from audio      AudioPlayer audioplayer = AudioPlayer();      await audioplayer.setSource(DeviceFileSource(audioPath!));      duration = await audioplayer.getDuration(); | 
