; WaveSurferSB - A wavesurfer.js v7 wrapper for SpiderBasic ; ; This library wraps the wavesurfer.js audio waveform player for use in SpiderBasic. ; Includes support for Timeline, Minimap, and Spectrogram plugins. ; wavesurfer.js v7: https://wavesurfer.xyz / https://github.com/katspaugh/wavesurfer.js ; ; Usage: ; IncludeFile "WaveSurferSB/WaveSurferSB.sbi" ; ; ; Load core + plugins (comma-separated: "timeline,minimap,spectrogram") ; WaveSurferSB::Download(@MyCallback(), "timeline,minimap,spectrogram") ; ; Procedure MyCallback(Success) ; If Success ; Define ws = WaveSurferSB::Create("#myContainer", WaveSurferSB::#DragToSeek) ; WaveSurferSB::TimelineCreate(ws) ; WaveSurferSB::MinimapCreate(ws, 50, "#777", "#333") ; WaveSurferSB::SpectrogramCreate(ws, "", 128, #True) ; WaveSurferSB::Load(ws, "audio.mp3") ; EndIf ; EndProcedure ; ; For wavesurfer.js documentation, see: https://wavesurfer.xyz/docs DeclareModule WaveSurferSB ;{ Initialization ; Plugins.s: comma-separated plugin names to load, e.g. "timeline,minimap,spectrogram" Declare Download(*Callback, Plugins.s = "", UseLocalFiles = #False) ;} ;{ Instance Management Declare Create(Container.s, Flags = 0) Declare Create_ex(Container.s, OptionsJSON.s) Declare Destroy(Instance) Declare Empty(Instance) ;} ;{ Audio Loading Declare Load(Instance, URL.s) Declare LoadWithPeaks(Instance, URL.s, PeaksJSON.s, Duration.d = 0.0) ;} ;{ Playback Control Declare Play(Instance) Declare PlayFrom(Instance, StartSeconds.d, EndSeconds.d = -1.0) Declare Pause(Instance) Declare PlayPause(Instance) Declare Stop(Instance) Declare IsPlaying(Instance) ;} ;{ Navigation Declare SetTime(Instance, TimeSeconds.d) Declare.d GetCurrentTime(Instance) Declare.d GetDuration(Instance) Declare SeekTo(Instance, Progress.d) ;} ;{ Volume & Speed Declare SetVolume(Instance, Volume.d) Declare.d GetVolume(Instance) Declare SetMuted(Instance, Muted) Declare SetPlaybackRate(Instance, Rate.d) Declare.d GetPlaybackRate(Instance) ;} ;{ Visual Options Declare SetOptions(Instance, OptionsJSON.s) Declare Zoom(Instance, MinPxPerSec.d) ;} ;{ Generic Plugin Registration Declare RegisterPlugin(Instance, PluginName.s, OptionsJSON.s = "{}") Declare DestroyPlugin(PluginInstance) ;} ;{ Timeline Plugin Declare TimelineCreate(Instance, Container.s = "", Height = 20) Declare TimelineCreate_ex(Instance, OptionsJSON.s) Declare TimelineDestroy(PluginInstance) ;} ;{ Minimap Plugin Declare MinimapCreate(Instance, Height = 50, WaveColor.s = "#999", ProgressColor.s = "#555", OverlayColor.s = "") Declare MinimapCreate_ex(Instance, OptionsJSON.s) Declare MinimapDestroy(PluginInstance) ;} ;{ Spectrogram Plugin Declare SpectrogramCreate(Instance, Container.s = "", Height = 128, Labels = #False) Declare SpectrogramCreate_ex(Instance, OptionsJSON.s) Declare SpectrogramDestroy(PluginInstance) ;} ;{ Events Declare OnReady(Instance, *Callback) Declare OnPlay(Instance, *Callback) Declare OnPause(Instance, *Callback) Declare OnFinish(Instance, *Callback) Declare OnTimeUpdate(Instance, *Callback) Declare OnSeeking(Instance, *Callback) Declare OnInteraction(Instance, *Callback) Declare OnClick(Instance, *Callback) Declare OnDecode(Instance, *Callback) Declare OnLoading(Instance, *Callback) Declare OnDestroy(Instance, *Callback) Declare OnEvent(Instance, EventName.s, *Callback) ;} ;{ Data Export Declare.s GetMediaElement(Instance) ;} ;{ Creation Flag Constants #Default = 0 #Normalize = 1 << 0 #AutoPlay = 1 << 1 #DragToSeek = 1 << 2 #HideScrollbar = 1 << 3 #AutoScroll = 1 << 4 #AutoCenter = 1 << 5 #SplitChannels = 1 << 6 #BarStyle = 1 << 7 ;} EndDeclareModule Module WaveSurferSB EnableExplicit ;{ Private Variables Global download_callback Global is_loaded = #False Global plugins_to_load.s = "" Global use_local.i = #False ;} ;{ Private Declarations Declare Handler_Download(url.s, success) Declare Handler_PluginDownload(url.s, success) Declare _HideAMD() Declare _RestoreAMD() Declare _LoadNextPlugin() ;} ; AMD/UMD Helpers Procedure _HideAMD() !window._ws_saved_module = (typeof module !== 'undefined') ? module : undefined; !window._ws_saved_exports = (typeof exports !== 'undefined') ? exports : undefined; !window._ws_saved_define = (typeof define !== 'undefined') ? define : undefined; !try { module = undefined; } catch(e) {} !try { exports = undefined; } catch(e) {} !try { define = undefined; } catch(e) {} EndProcedure Procedure _RestoreAMD() !try { if (window._ws_saved_module !== undefined) module = window._ws_saved_module; } catch(e) {} !try { if (window._ws_saved_exports !== undefined) exports = window._ws_saved_exports; } catch(e) {} !try { if (window._ws_saved_define !== undefined) define = window._ws_saved_define; } catch(e) {} EndProcedure ; Plugin Loading Chain Procedure _LoadNextPlugin() Protected plugin.s, url.s ; Pop the first plugin from the comma-separated list !v_plugin = wavesurfersb$g_plugins_to_load.split(',')[0] || ''; !wavesurfersb$g_plugins_to_load = wavesurfersb$g_plugins_to_load.split(',').slice(1).join(','); !v_plugin = v_plugin.trim(); Protected check !v_check = (v_plugin === ''); If check ; All plugins loaded - restore AMD and call user callback _RestoreAMD() is_loaded = #True !wavesurfersb$g_download_callback(1); ProcedureReturn EndIf If use_local url = "LocalFiles/JS/wavesurfer-" + plugin + ".min.js" Else url = "https://unpkg.com/wavesurfer.js@7/dist/plugins/" + plugin + ".min.js" EndIf LoadScript(url, @Handler_PluginDownload(), #PB_Script_JavaScript) EndProcedure ; Initialization Procedure Download(*Callback, Plugins.s = "", UseLocalFiles = #False) download_callback = *Callback plugins_to_load = Plugins use_local = UseLocalFiles _HideAMD() If UseLocalFiles LoadScript("LocalFiles/JS/wavesurfer.min.js", @Handler_Download(), #PB_Script_JavaScript) Else LoadScript("https://unpkg.com/wavesurfer.js@7/dist/wavesurfer.min.js", @Handler_Download(), #PB_Script_JavaScript) EndIf EndProcedure ; Instance Management Procedure Create(Container.s, Flags = 0) Protected Instance ; Build options object in JavaScript !var _opts = { container: v_container }; If Flags & #Normalize !_opts.normalize = true; EndIf If Flags & #AutoPlay !_opts.autoplay = true; EndIf If Flags & #DragToSeek !_opts.dragToSeek = true; EndIf If Flags & #HideScrollbar !_opts.hideScrollbar = true; EndIf If Flags & #AutoScroll !_opts.autoScroll = true; EndIf If Flags & #AutoCenter !_opts.autoCenter = true; EndIf If Flags & #SplitChannels !_opts.splitChannels = [{}]; EndIf If Flags & #BarStyle !_opts.barWidth = 2; !_opts.barGap = 1; !_opts.barRadius = 2; EndIf !v_instance = WaveSurfer.create(_opts); ProcedureReturn Instance EndProcedure Procedure Create_ex(Container.s, OptionsJSON.s) Protected Instance !var _opts; !try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } !_opts.container = v_container; !v_instance = WaveSurfer.create(_opts); ProcedureReturn Instance EndProcedure Procedure Destroy(Instance) !if (v_instance && typeof v_instance.destroy === 'function') { ! v_instance.destroy(); !} EndProcedure Procedure Empty(Instance) !if (v_instance && typeof v_instance.empty === 'function') { ! v_instance.empty(); !} EndProcedure ; Audio Loading Procedure Load(Instance, URL.s) !if (v_instance) v_instance.load(v_url); EndProcedure Procedure LoadWithPeaks(Instance, URL.s, PeaksJSON.s, Duration.d = 0.0) !if (v_instance) { ! var _peaks; ! try { _peaks = JSON.parse(v_peaksjson); } catch(e) { _peaks = undefined; } ! var _dur = v_duration > 0 ? v_duration : undefined; ! v_instance.load(v_url, _peaks, _dur); !} EndProcedure ; Playback Control Procedure Play(Instance) !if (v_instance) v_instance.play(); EndProcedure Procedure PlayFrom(Instance, StartSeconds.d, EndSeconds.d = -1.0) !if (v_instance) { ! if (v_endseconds >= 0) { ! v_instance.play(v_startseconds, v_endseconds); ! } else { ! v_instance.play(v_startseconds); ! } !} EndProcedure Procedure Pause(Instance) !if (v_instance) v_instance.pause(); EndProcedure Procedure PlayPause(Instance) !if (v_instance) v_instance.playPause(); EndProcedure Procedure Stop(Instance) !if (v_instance) v_instance.stop(); EndProcedure Procedure IsPlaying(Instance) Protected Result = #False !if (v_instance) v_result = v_instance.isPlaying(); ProcedureReturn Result EndProcedure ; Navigation Procedure SetTime(Instance, TimeSeconds.d) !if (v_instance) v_instance.setTime(v_timeseconds); EndProcedure Procedure.d GetCurrentTime(Instance) Protected.d Result = 0.0 !if (v_instance) v_result = v_instance.getCurrentTime(); ProcedureReturn Result EndProcedure Procedure.d GetDuration(Instance) Protected.d Result = 0.0 !if (v_instance) v_result = v_instance.getDuration(); ProcedureReturn Result EndProcedure Procedure SeekTo(Instance, Progress.d) !if (v_instance) v_instance.seekTo(v_progress); EndProcedure ; Volume & Speed Procedure SetVolume(Instance, Volume.d) !if (v_instance) v_instance.setVolume(v_volume); EndProcedure Procedure.d GetVolume(Instance) Protected.d Result = 1.0 !if (v_instance) v_result = v_instance.getVolume(); ProcedureReturn Result EndProcedure Procedure SetMuted(Instance, Muted) !if (v_instance) v_instance.setMuted(!!v_muted); EndProcedure Procedure SetPlaybackRate(Instance, Rate.d) !if (v_instance) v_instance.setPlaybackRate(v_rate); EndProcedure Procedure.d GetPlaybackRate(Instance) Protected.d Result = 1.0 !if (v_instance) v_result = v_instance.getPlaybackRate(); ProcedureReturn Result EndProcedure ; Visual Options Procedure SetOptions(Instance, OptionsJSON.s) !if (v_instance) { ! var _opts; ! try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } ! v_instance.setOptions(_opts); !} EndProcedure Procedure Zoom(Instance, MinPxPerSec.d) !if (v_instance) v_instance.zoom(v_minpxpersec); EndProcedure ; Generic Plugin Registration Procedure RegisterPlugin(Instance, PluginName.s, OptionsJSON.s = "{}") Protected PluginInstance !if (v_instance && WaveSurfer[v_pluginname]) { ! var _opts; ! try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } ! v_plugininstance = v_instance.registerPlugin(WaveSurfer[v_pluginname].create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure DestroyPlugin(PluginInstance) !if (v_plugininstance && typeof v_plugininstance.destroy === 'function') { ! v_plugininstance.destroy(); !} EndProcedure ; Timeline Plugin Procedure TimelineCreate(Instance, Container.s = "", Height = 20) Protected PluginInstance !if (v_instance && WaveSurfer.Timeline) { ! var _opts = { height: v_height }; ! if (v_container && v_container !== '') _opts.container = v_container; ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Timeline.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure TimelineCreate_ex(Instance, OptionsJSON.s) Protected PluginInstance !if (v_instance && WaveSurfer.Timeline) { ! var _opts; ! try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Timeline.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure TimelineDestroy(PluginInstance) DestroyPlugin(PluginInstance) EndProcedure ; Minimap Plugin Procedure MinimapCreate(Instance, Height = 50, WaveColor.s = "#999", ProgressColor.s = "#555", OverlayColor.s = "") Protected PluginInstance !if (v_instance && WaveSurfer.Minimap) { ! var _opts = { ! height: v_height, ! waveColor: v_wavecolor, ! progressColor: v_progresscolor ! }; ! if (v_overlaycolor && v_overlaycolor !== '') _opts.overlayColor = v_overlaycolor; ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Minimap.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure MinimapCreate_ex(Instance, OptionsJSON.s) Protected PluginInstance !if (v_instance && WaveSurfer.Minimap) { ! var _opts; ! try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Minimap.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure MinimapDestroy(PluginInstance) DestroyPlugin(PluginInstance) EndProcedure ; Spectrogram Plugin Procedure SpectrogramCreate(Instance, Container.s = "", Height = 128, Labels = #False) Protected PluginInstance !if (v_instance && WaveSurfer.Spectrogram) { ! var _opts = { ! height: v_height, ! labels: !!v_labels ! }; ! if (v_container && v_container !== '') _opts.container = v_container; ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Spectrogram.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure SpectrogramCreate_ex(Instance, OptionsJSON.s) Protected PluginInstance !if (v_instance && WaveSurfer.Spectrogram) { ! var _opts; ! try { _opts = JSON.parse(v_optionsjson); } catch(e) { _opts = {}; } ! v_plugininstance = v_instance.registerPlugin(WaveSurfer.Spectrogram.create(_opts)); !} ProcedureReturn PluginInstance EndProcedure Procedure SpectrogramDestroy(PluginInstance) DestroyPlugin(PluginInstance) EndProcedure ; Events Procedure OnReady(Instance, *Callback) !if (v_instance) v_instance.on('ready', function(duration) { p_callback(duration); }); EndProcedure Procedure OnPlay(Instance, *Callback) !if (v_instance) v_instance.on('play', function() { p_callback(); }); EndProcedure Procedure OnPause(Instance, *Callback) !if (v_instance) v_instance.on('pause', function() { p_callback(); }); EndProcedure Procedure OnFinish(Instance, *Callback) !if (v_instance) v_instance.on('finish', function() { p_callback(); }); EndProcedure Procedure OnTimeUpdate(Instance, *Callback) !if (v_instance) v_instance.on('timeupdate', function(currentTime) { p_callback(currentTime); }); EndProcedure Procedure OnSeeking(Instance, *Callback) !if (v_instance) v_instance.on('seeking', function(currentTime) { p_callback(currentTime); }); EndProcedure Procedure OnInteraction(Instance, *Callback) !if (v_instance) v_instance.on('interaction', function(newTime) { p_callback(newTime); }); EndProcedure Procedure OnClick(Instance, *Callback) !if (v_instance) v_instance.on('click', function(relativeX) { p_callback(relativeX); }); EndProcedure Procedure OnDecode(Instance, *Callback) !if (v_instance) v_instance.on('decode', function(duration) { p_callback(duration); }); EndProcedure Procedure OnLoading(Instance, *Callback) !if (v_instance) v_instance.on('loading', function(percent) { p_callback(percent); }); EndProcedure Procedure OnDestroy(Instance, *Callback) !if (v_instance) v_instance.on('destroy', function() { p_callback(); }); EndProcedure Procedure OnEvent(Instance, EventName.s, *Callback) !if (v_instance) v_instance.on(v_eventname, function() { p_callback(); }); EndProcedure ; Data Export Procedure.s GetMediaElement(Instance) Protected Result.s = "" !if (v_instance) { ! var _media = v_instance.getMediaElement(); ! if (_media) v_result = _media.outerHTML || ''; !} ProcedureReturn Result EndProcedure ; Private Procedures Procedure Handler_Download(url.s, success) If success ; Core loaded - now load plugins if any If plugins_to_load <> "" _LoadNextPlugin() Else ; No plugins requested - all done _RestoreAMD() is_loaded = #True !wavesurfersb$g_download_callback(1); EndIf Else _RestoreAMD() !wavesurfersb$g_download_callback(0); EndIf EndProcedure Procedure Handler_PluginDownload(url.s, success) If success ; Plugin loaded - continue chain with next plugin _LoadNextPlugin() Else _RestoreAMD() !wavesurfersb$g_download_callback(0); EndIf EndProcedure EndModule ; IDE Options = SpiderBasic 3.20 (Windows - x86) ; Folding = BAAAAAAAAAAg ; iOSAppOrientation = 0 ; AndroidAppCode = 0 ; AndroidAppOrientation = 0 ; EnableXP ; DPIAware ; CompileSourceDirectory