Created
April 17, 2022 10:59
-
-
Save nkrapivin/6ae530e8b017bb48d78511f7514c1f09 to your computer and use it in GitHub Desktop.
BnvibCrap - a weird bnvib player written in GML
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function BnvibCrap() { | |
// a safe guard to prevent from calling this file as BnvibCrap(); | |
/* example usage: | |
// create: | |
var _pl = new BnvibPlayer("test.bnvib"); | |
playerSlot = // get player gamepad slot here somehow; | |
// step: | |
if (!is_undefined(_pl)) { | |
if (!_pl.stepAll(playerSlot)) { // huh? step failed? | |
var _stopstate = _pl.getstate(); | |
// observe the state here | |
} | |
} | |
*/ | |
return "see example usage above ^^^"; | |
} | |
// key:string, value:number (bnvib file id) | |
global._bnvibs_map = ds_map_create(); | |
/// @desc bnvib file load cache, if file is already loaded it'll reuse the ids | |
/// @param {String} bnvibFilePathString bnvib file to load, must be in included files | |
function BnvibLoadFile(bnvibFilePathString) { | |
if (!is_string(bnvibFilePathString)) { | |
throw string("\nBnvib path must be a string, got " + typeof(bnvibFilePathString)); | |
} | |
if (ds_map_exists(global._bnvibs_map, bnvibFilePathString)) { | |
return ds_map_find_value(global._bnvibs_map, bnvibFilePathString); | |
} | |
var _result = switch_bnvib_load(bnvibFilePathString); | |
if (_result < 0) { | |
throw string("\nUnable to load bnvib " + string(bnvibFilePathString) + "," + string(_result)); | |
} | |
ds_map_add(global._bnvibs_map, bnvibFilePathString, _result); | |
return _result; | |
} | |
/// @param {String} [bnvibFilePathString] bnvib file to target, if already loaded will reuse ids. | |
/// @param {Any} [userdataAnyOpt] optional userdata the player will contain. | |
function BnvibPlayer(bnvibFilePathString, userdataAnyOpt) constructor { | |
/// @desc bnvib file id, if it's undefined then create a player with no file bound | |
handle = is_undefined(bnvibFilePathString) ? -1 : BnvibLoadFile(bnvibFilePathString); | |
/// @desc current playback position | |
pos = 0; | |
/// @desc skip time for loop interval, if >0 then we're in an interval and skipping time | |
skip = 0; | |
/// @desc paused flag | |
ispaused = false; | |
/// @desc user supplied data specific to this instance, can be of any type | |
userdata = userdataAnyOpt; | |
/// @desc Destroys this player instance, you cannot use it again (unless you call setfile which revives it!) | |
dispose = function() { | |
// unset both bnvib id and the playback position to some negative values | |
handle = -1; | |
pos = -1; | |
}; | |
/// @desc Stops the player without pausing, unpausing will NOT unstop the player | |
/// to unstop a player call setfile() | |
stop = function() { | |
pos = -1; | |
}; | |
/// @param {String} newBnvibPath new bnvib file path | |
/// @desc Allows to swap the currently playing file, WILL reset the position | |
setfile = function(newBnvibPath) { | |
pos = 0; | |
handle = BnvibLoadFile(newBnvibPath); | |
// the pause flag is not reset, if the player is paused by you, you must unpause it yourself. | |
}; | |
/// @param {Real} step Sample step, ideally should be equal to sampleRate/fps, but since I hate my life, it's 1. | |
/// @desc Advances the play position, can be used outside of step() but better not to! | |
advance = function(step = 1) { | |
if (handle < 0) { | |
throw "\nThis bnvib player has been disposed."; | |
} | |
if (pos < 0 || ispaused) { | |
return false; | |
} | |
// we're inside loop interval, do not increment pos but decrement the interval timer. | |
if (skip > 0) { | |
skip -= step; | |
if (skip < 0) { | |
skip = 0; | |
} | |
return true; | |
} | |
var _rate = switch_bnvib_get_sampling_rate(handle); | |
if (_rate <= 0) { | |
throw "\nInvalid or disposed bnvib file"; | |
} | |
pos += step; | |
var _filelength = switch_bnvib_get_length(handle); | |
var _isloop = switch_bnvib_is_looping(handle) != 0; | |
if (_isloop) { // looping bnvibs: | |
var _loopstart = switch_bnvib_get_loop_start_position(handle); | |
var _loopend = switch_bnvib_get_loop_end_position(handle); | |
var _loopinterval = switch_bnvib_get_loop_interval(handle); | |
if (pos >= _loopend) { | |
pos = _loopstart; | |
skip = _loopinterval; | |
} | |
} | |
else { // non-looping bnvibs: | |
// if we're at the end, just stop without disposing. | |
if (pos >= _filelength) { | |
pos = -1; | |
} | |
} | |
return true; | |
}; | |
/// @desc Performs a vibration step on chosen motor | |
/// @param {Real} targetSlotReal On which slot to play the vibration step | |
/// @param {Real} targetMotorReal The 'switch_controller_motor_' constant | |
/// @param {Bool} advancePositionBool false will play without advancing the position | |
step = function(targetSlotReal, targetMotorReal, advancePositionBool = true) { | |
if (handle < 0) { | |
throw "\nThis bnvib player has been disposed."; | |
} | |
if (targetSlotReal < 0 || !gamepad_is_connected(targetSlotReal) || pos < 0 || ispaused) { | |
return false; | |
} | |
// if we're not skipping any samples. | |
if (skip <= 0) { | |
var _values = switch_bnvib_get_value(handle, pos); | |
switch_controller_vibrate_hd( | |
targetSlotReal, | |
targetMotorReal, | |
_values[@ 0], | |
_values[@ 1], | |
_values[@ 2], | |
_values[@ 3] | |
); | |
} | |
if (advancePositionBool) { | |
return advance(); | |
} | |
return false; | |
}; | |
/// @desc Performs a vibration step on both motors | |
/// @param {Real} targetSlot On which slot to play the vibration step | |
/// @param {Bool} advancePositionBool false will play without advancing the position | |
stepAll = function(targetSlotReal, advancePositionBool = true) { | |
// FYI: switch_controller_motor_left == switch_controller_motor_single | |
// o_O | |
// step() will also check if we're paused or stopped | |
if (!step(targetSlotReal, switch_controller_motor_left, false)) { | |
return false; | |
} | |
if (!step(targetSlotReal, switch_controller_motor_right, false)) { | |
return false; | |
} | |
if (advancePositionBool) { | |
return advance(); | |
} | |
return true; | |
}; | |
/// @desc Returns the overall state of this player instance as a string | |
getstate = function() { | |
if (handle < 0) { | |
return "disposed"; | |
} | |
if (pos < 0) { | |
return "stopped"; | |
} | |
if (ispaused) { | |
return "paused"; | |
} | |
return "playing"; | |
}; | |
/// @desc Returns overview information about this player instance | |
toString = function() { | |
return string("BnvibPlayer:handle=" + string(handle) + ",pos=" + string(pos) + ",paused=" + string(ispaused)); | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment