Skip to content

Instantly share code, notes, and snippets.

@nkrapivin
Created April 17, 2022 10:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkrapivin/6ae530e8b017bb48d78511f7514c1f09 to your computer and use it in GitHub Desktop.
Save nkrapivin/6ae530e8b017bb48d78511f7514c1f09 to your computer and use it in GitHub Desktop.
BnvibCrap - a weird bnvib player written in GML
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