From 4836cae3faa73c6065f1edd8690fcc845415fe32 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Tue, 9 Apr 2024 20:07:36 +0200 Subject: [PATCH] added speaker peripheral --- src/bin/Speaker.hx | 95 +++++++++++++++++++++++++++ src/kernel/peripherals/Peripherals.hx | 13 ++++ src/kernel/peripherals/Speaker.hx | 61 +++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 src/bin/Speaker.hx create mode 100644 src/kernel/peripherals/Speaker.hx diff --git a/src/bin/Speaker.hx b/src/bin/Speaker.hx new file mode 100644 index 0000000..d8289be --- /dev/null +++ b/src/bin/Speaker.hx @@ -0,0 +1,95 @@ +package bin; + +import kernel.peripherals.Peripherals.Peripheral; +import lib.CLIAppBase; + +using tink.CoreApi; + +@:build(macros.Binstore.includeBin("Speaker", ["speaker", "sp"])) +class Speaker extends CLIAppBase { + public function new() { + registerSyncSubcommand("note", (args) -> { + if (args.length < 2) { + handle.writeLine("Not enough args"); + return false; + } + + var sp = Peripheral.getSpeaker(args[0]); + + var note = args[1]; + var r; + + if (args.length > 3) { + var volume = Std.parseFloat(args[2]); + if (volume == null) { + handle.writeLine("Failed to parse volume"); + return false; + } + + if (args.length > 4) { + var pitch = Std.parseInt(args[3]); + if (pitch == null) { + handle.writeLine("Failed to parse pitch"); + return false; + } + + r = sp.playNote(note, volume, pitch); + } else { + r = sp.playNote(note, volume); + } + } else { + r = sp.playNote(note); + } + + switch r { + case Failure(failure): + handle.writeLine(failure); + return false; + case Success(_): + return true; + } + }, " [pitch] [volume]"); + + registerSyncSubcommand("sound", (args) -> { + if (args.length < 2) { + handle.writeLine("Not enough args"); + return false; + } + + var sp = Peripheral.getSpeaker(args[0]); + + var sound = args[1]; + var r; + + if (args.length > 3) { + var volume = Std.parseFloat(args[2]); + if (volume == null) { + handle.writeLine("Failed to parse volume"); + return false; + } + + if (args.length > 4) { + var pitch = Std.parseFloat(args[3]); + if (pitch == null) { + handle.writeLine("Failed to parse pitch"); + return false; + } + + r = sp.playSound(sound, volume, pitch); + } else { + r = sp.playSound(sound, volume); + } + } else { + r = sp.playSound(sound); + } + + switch r { + case Failure(failure): + handle.writeLine(failure); + return false; + case Success(_): + return true; + } + }, " [volume] [pitch]"); + } +} diff --git a/src/kernel/peripherals/Peripherals.hx b/src/kernel/peripherals/Peripherals.hx index bee3f03..3030396 100644 --- a/src/kernel/peripherals/Peripherals.hx +++ b/src/kernel/peripherals/Peripherals.hx @@ -81,6 +81,8 @@ class Peripheral { return getModem(addr); case Printer.TYPE_NAME: return getPrinter(addr); + case Speaker.TYPE_NAME: + return getSpeaker(addr); case "redstone": return getRedstone(addr); } @@ -158,4 +160,15 @@ class Peripheral { public static function getAllComputers():Array { return [for (addr in findAddrByType(Computer.TYPE_NAME)) new Computer(addr)]; } + + public static function getSpeaker(addr:String):Null { + var addr = safeGetAddr(addr, Speaker.TYPE_NAME); + if (addr == null) + return null; + return new Speaker(addr); + } + + public static function getAllSpeakers():Array { + return [for (addr in findAddrByType(Speaker.TYPE_NAME)) new Speaker(addr)]; + } } diff --git a/src/kernel/peripherals/Speaker.hx b/src/kernel/peripherals/Speaker.hx new file mode 100644 index 0000000..3367b1d --- /dev/null +++ b/src/kernel/peripherals/Speaker.hx @@ -0,0 +1,61 @@ +package kernel.peripherals; + +import cc.Peripheral; + +using tink.CoreApi; + +class Speaker implements IPeripheral { + public static inline final TYPE_NAME:String = "speaker"; + + private final addr:String; + + public function new(addr:String) { + this.addr = addr; + } + + public function getType():String { + return Speaker.TYPE_NAME; + } + + public function getAddr():String { + return this.addr; + } + + /** + Plays a note block note through the speaker. + The pitch argument uses semitones as the unit. This directly maps to the number of clicks on a note block. + For reference, 0, 12, and 24 map to F#, and 6 and 18 map to C. + A maximum of 8 notes can be played in a single tick. If this limit is hit, this function will return an error. + **/ + public function playNote(instrument:String, ?volume:Float = 1.0, ?pitch:Int = 12):Outcome { + if (Peripheral.call(addr, "playNote", instrument, volume, pitch)) { + return Success(null); + } else { + return Failure("maximum reached"); + } + } + + public function playSound(sound:String, ?volume:Float = 1.0, ?pitch:Float = 1.0):Outcome { + try { + if (Peripheral.call(addr, "playSound", sound, volume, pitch)) { + return Success(null); + } else { + return Failure("Sound still playing"); + } + } catch (e) { + return Failure("Sound does not exist"); + } + } + + public function playAudio(buffer:Array, ?volume:Float = 1.0):Outcome { + try { + if (Peripheral.call(addr, "playAudio", buffer, volume)) { + return Success(null); + } else { + return Failure("Buffer full"); + } + } catch (e) { + return Failure("Buffer malformed"); + } + } +}