From 9ca5c63afd753053154c097a5ebd88d23201c2d2 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 17 Jan 2026 02:05:24 +0800 Subject: [PATCH] :drunk: Messing around werid stuff --- assets/midi/never-gonna-give-you-up.mid | Bin 0 -> 10405 bytes lib/pods/audio.dart | 111 ++++++++++++++++++++++++ macos/Podfile.lock | 7 -- pubspec.lock | 8 ++ pubspec.yaml | 2 + 5 files changed, 121 insertions(+), 7 deletions(-) create mode 100644 assets/midi/never-gonna-give-you-up.mid diff --git a/assets/midi/never-gonna-give-you-up.mid b/assets/midi/never-gonna-give-you-up.mid new file mode 100644 index 0000000000000000000000000000000000000000..5ccee5d1f356fdd096727fd85f5859f8cb43c430 GIT binary patch literal 10405 zcmeHN+e#ck5N)Fbe;^PdfknhCMp;K7ViX@nOdt|TApXGoLFSY4XQpaq zYWDP*>29Bb$<9NwnXc2_HPuz8Pmh_LfBo#7dns*cDW9DG{N~*DFZcLqW#z@|RrmOD zdG*a(_qhD(!~K`rcZ2EO&G#RJ?f3UL4-a>@JMOo0#c-JA!{#?D4(0h!o~z%iIFRQ9 zd9Hr5Vqc#3<+=LJitC{(rqcGLf6uvmD(zbASJHO|{b$mDCHao~G{uW~ZOJa6${uk+?Sp!;Zb96LAuHQpPSoYw0+sS!_?;Q60A zzj~cl-XB}{BIT@J=T#h{=M?5th@2J`M| ze@o|ud{I8Jdl_R?r{EdGc023wUK_wf`Hsh6t})*c*30uiEF0aybwP7^IL&Lz$x(T3 z`I;T`Hx@tCN}=_-bRJ`Iy_nA9aVee0_>j(HobA2%LOQQ~Z!xUuM~y3TQ?L7a-DmYP zF6(Tr50!tc2H95URMO7*#^;dbCh{O-mgirIg<88<-6E@g>@fexh`xUmG2mfd18FW80I^++j?Dm z$5>o1#&MXz9p~V-7CRE`E&TYMnI#r?z@cB zda-!0&Ek==FDmb`KI(Pe{62-}t>#DncigJZluMY`F>g3-jMZ}w_57$qBP{~o1vFZV z?-+-C$2R7>ke&H1fGhuBi0Kr@s2_O7u-(pj)WZRcr-SkPPC)14w>B?cG{1LGeZpKG yp60?eTlZSVV*bYBhjqYnSp2$l9%FI6n9k#IDV@jokj`Tq_)a=6`hD;5!2JPjP6|^1 literal 0 HcmV?d00001 diff --git a/lib/pods/audio.dart b/lib/pods/audio.dart index 20830917..2917b271 100644 --- a/lib/pods/audio.dart +++ b/lib/pods/audio.dart @@ -1,7 +1,11 @@ +import 'dart:math' as math; + +import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:just_audio/just_audio.dart'; import 'package:island/pods/config.dart'; import 'package:audio_session/audio_session.dart'; +import 'package:dart_midi_pro/dart_midi_pro.dart'; final sfxPlayerProvider = Provider((ref) { final player = AudioPlayer(); @@ -63,3 +67,110 @@ void playMessageSfx(WidgetRef ref) { if (!settings.soundEffects) return; _playSfx('assets/audio/messages.mp3', 0.75); } + +class MiniSampleSynth { + final String sampleAsset; + final int baseNote; // MIDI note of the sample (usually 72 = C5 for lower pitch playback) + + AudioPlayer? currentPlayer; + + MiniSampleSynth({required this.sampleAsset, this.baseNote = 72}); + + Future playMidiAsset(String midiAsset) async { + final data = await rootBundle.load(midiAsset); + final midi = MidiParser().parseMidiFromBuffer(data.buffer.asUint8List()); + + for (final track in midi.tracks) { + int currentTick = 0; + + for (final event in track) { + currentTick += event.deltaTime; + + if (event is NoteOnEvent && event.velocity > 0) { + final note = event.noteNumber; + final durationTicks = _estimateDuration(track, event); + final durationMs = _ticksToMs(durationTicks, midi); + + _scheduleNote( + note: note, + startMs: _ticksToMs(currentTick, midi), + durationMs: durationMs, + ); + } + } + } + } + + void _scheduleNote({ + required int note, + required int startMs, + required int durationMs, + }) { + Future.delayed(Duration(milliseconds: startMs), () async { + // Stop any currently playing note + if (currentPlayer != null) { + await currentPlayer!.stop(); + await currentPlayer!.dispose(); + currentPlayer = null; + } + + final player = AudioPlayer(); + currentPlayer = player; + + await player.setAudioSource(AudioSource.asset(sampleAsset)); + final speed = _noteToSpeed(note); + await player.setSpeed(speed); + await player.play(); + + Future.delayed(Duration(milliseconds: durationMs), () async { + if (currentPlayer == player) { + await player.stop(); + await player.dispose(); + currentPlayer = null; + } + }); + }); + } + + double _noteToSpeed(int note) { + return math.pow(2, (note - baseNote) / 12).toDouble(); + } + + int _getTempo(MidiFile midi) { + for (var track in midi.tracks) { + for (var event in track) { + if (event is SetTempoEvent) { + return event.microsecondsPerBeat; + } + } + } + return 500000; // default 120 BPM + } + + int _ticksToMs(int ticks, MidiFile midi) { + final tempo = _getTempo(midi); + final ticksPerBeat = midi.header.ticksPerBeat ?? 480; + + return ((ticks * tempo) / ticksPerBeat / 1000).round(); + } + + int _estimateDuration(List track, NoteOnEvent on) { + int ticks = 0; + bool started = false; + + for (final e in track) { + if (e == on) { + started = true; + continue; + } + if (!started) continue; + + ticks += e.deltaTime; + + if (e is NoteOffEvent && e.noteNumber == on.noteNumber) { + return ticks; + } + } + return 200; // fallback + } +} \ No newline at end of file diff --git a/macos/Podfile.lock b/macos/Podfile.lock index b955f852..113e621b 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -204,9 +204,6 @@ PODS: - FlutterMacOS - pasteboard (0.0.1): - FlutterMacOS - - path_provider_foundation (0.0.1): - - Flutter - - FlutterMacOS - PromisesObjC (2.4.0) - PromisesSwift (2.4.0): - PromisesObjC (= 2.4.0) @@ -296,7 +293,6 @@ DEPENDENCIES: - media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`) - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) - pasteboard (from `Flutter/ephemeral/.symlinks/plugins/pasteboard/macos`) - - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) - protocol_handler_macos (from `Flutter/ephemeral/.symlinks/plugins/protocol_handler_macos/macos`) - record_macos (from `Flutter/ephemeral/.symlinks/plugins/record_macos/macos`) - screen_retriever_macos (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever_macos/macos`) @@ -397,8 +393,6 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos pasteboard: :path: Flutter/ephemeral/.symlinks/plugins/pasteboard/macos - path_provider_foundation: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin protocol_handler_macos: :path: Flutter/ephemeral/.symlinks/plugins/protocol_handler_macos/macos record_macos: @@ -476,7 +470,6 @@ SPEC CHECKSUMS: OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: f0052d280d17aa382b932f399edf32507174e870 pasteboard: 278d8100149f940fb795d6b3a74f0720c890ecb7 - path_provider_foundation: bb55f6dbba17d0dccd6737fe6f7f34fbd0376880 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851 protocol_handler_macos: f9cd7b13bcaf6b0425f7410cbe52376cb843a936 diff --git a/pubspec.lock b/pubspec.lock index 41a17e27..7b018bd4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -417,6 +417,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.1" + dart_midi_pro: + dependency: "direct main" + description: + name: dart_midi_pro + sha256: "9a0273c92c0336e5694c7318fd936f64f06e938a936dd5fac6563c39954b7f6d" + url: "https://pub.dev" + source: hosted + version: "1.0.4+2" dart_style: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index c660f10c..0d4e4409 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -174,6 +174,7 @@ dependencies: video_thumbnail: ^0.5.6 just_audio: ^0.10.5 audio_session: ^0.2.2 + dart_midi_pro: ^1.0.4+2 dev_dependencies: flutter_test: @@ -207,6 +208,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: + - assets/midi/ - assets/i18n/ - assets/images/ - assets/images/oidc/