From f6f9ad3985b41efa4c1d63ab1892196814a908d1 Mon Sep 17 00:00:00 2001 From: EliteMasterEric Date: Fri, 2 Feb 2024 21:53:45 -0500 Subject: [PATCH] Completed functionality for offset window. --- source/funkin/audio/waveform/WaveformData.hx | 30 +- .../ui/debug/charting/ChartEditorState.hx | 39 +- .../commands/SetAudioOffsetCommand.hx | 109 ++++++ .../handlers/ChartEditorAudioHandler.hx | 7 +- .../ChartEditorImportExportHandler.hx | 7 +- .../handlers/ChartEditorThemeHandler.hx | 26 +- .../toolboxes/ChartEditorOffsetsToolbox.hx | 369 +++++++++++++++--- 7 files changed, 488 insertions(+), 99 deletions(-) create mode 100644 source/funkin/ui/debug/charting/commands/SetAudioOffsetCommand.hx diff --git a/source/funkin/audio/waveform/WaveformData.hx b/source/funkin/audio/waveform/WaveformData.hx index 11d3ff641..31f8dfe02 100644 --- a/source/funkin/audio/waveform/WaveformData.hx +++ b/source/funkin/audio/waveform/WaveformData.hx @@ -113,7 +113,7 @@ class WaveformData */ public function lenSeconds():Float { - return lenSamples() / sampleRate; + return inline lenSamples() / sampleRate; } /** @@ -121,7 +121,7 @@ class WaveformData */ public function secondsToIndex(seconds:Float):Int { - return Std.int(seconds * pointsPerSecond()); + return Std.int(seconds * inline pointsPerSecond()); } /** @@ -129,7 +129,7 @@ class WaveformData */ public function indexToSeconds(index:Int):Float { - return index / pointsPerSecond(); + return index / inline pointsPerSecond(); } /** @@ -216,7 +216,7 @@ class WaveformDataChannel public function minSample(i:Int) { var offset = (i * parent.channels + this.channelId) * 2; - return parent.get(offset); + return inline parent.get(offset); } /** @@ -224,7 +224,7 @@ class WaveformDataChannel */ public function minSampleMapped(i:Int) { - return minSample(i) / parent.maxSampleValue(); + return inline minSample(i) / inline parent.maxSampleValue(); } /** @@ -233,10 +233,10 @@ class WaveformDataChannel */ public function minSampleRange(start:Int, end:Int) { - var min = parent.maxSampleValue(); + var min = inline parent.maxSampleValue(); for (i in start...end) { - var sample = minSample(i); + var sample = inline minSample(i); if (sample < min) min = sample; } return min; @@ -247,7 +247,7 @@ class WaveformDataChannel */ public function minSampleRangeMapped(start:Int, end:Int) { - return minSampleRange(start, end) / parent.maxSampleValue(); + return inline minSampleRange(start, end) / inline parent.maxSampleValue(); } /** @@ -256,7 +256,7 @@ class WaveformDataChannel public function maxSample(i:Int) { var offset = (i * parent.channels + this.channelId) * 2 + 1; - return parent.get(offset); + return inline parent.get(offset); } /** @@ -264,7 +264,7 @@ class WaveformDataChannel */ public function maxSampleMapped(i:Int) { - return maxSample(i) / parent.maxSampleValue(); + return inline maxSample(i) / inline parent.maxSampleValue(); } /** @@ -273,10 +273,10 @@ class WaveformDataChannel */ public function maxSampleRange(start:Int, end:Int) { - var max = -parent.maxSampleValue(); + var max = -(inline parent.maxSampleValue()); for (i in start...end) { - var sample = maxSample(i); + var sample = inline maxSample(i); if (sample > max) max = sample; } return max; @@ -287,18 +287,18 @@ class WaveformDataChannel */ public function maxSampleRangeMapped(start:Int, end:Int) { - return maxSampleRange(start, end) / parent.maxSampleValue(); + return inline maxSampleRange(start, end) / inline parent.maxSampleValue(); } public function setMinSample(i:Int, value:Int) { var offset = (i * parent.channels + this.channelId) * 2; - parent.set(offset, value); + inline parent.set(offset, value); } public function setMaxSample(i:Int, value:Int) { var offset = (i * parent.channels + this.channelId) * 2 + 1; - parent.set(offset, value); + inline parent.set(offset, value); } } diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index ec6d36b07..719f6aceb 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -1,5 +1,6 @@ package funkin.ui.debug.charting; +import funkin.ui.debug.charting.toolboxes.ChartEditorOffsetsToolbox; import funkin.util.logging.CrashHandler; import haxe.ui.containers.HBox; import haxe.ui.containers.Grid; @@ -1098,7 +1099,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState * `null` until vocal track(s) are loaded. * When switching characters, the elements of the VoicesGroup will be swapped to match the new character. */ - var audioVocalTrackGroup:Null = null; + var audioVocalTrackGroup:VoicesGroup = new VoicesGroup(); /** * The audio waveform visualization for the inst/vocals. @@ -2257,8 +2258,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Initialize the song chart data. songChartData = new Map(); - - audioVocalTrackGroup = new VoicesGroup(); } /** @@ -2889,13 +2888,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState menubarItemVolumeVocalsPlayer.onChange = event -> { var volume:Float = event.value.toFloat() / 100.0; - if (audioVocalTrackGroup != null) audioVocalTrackGroup.playerVolume = volume; + audioVocalTrackGroup.playerVolume = volume; menubarLabelVolumeVocalsPlayer.text = 'Player - ${Std.int(event.value)}%'; }; menubarItemVolumeVocalsOpponent.onChange = event -> { var volume:Float = event.value.toFloat() / 100.0; - if (audioVocalTrackGroup != null) audioVocalTrackGroup.opponentVolume = volume; + audioVocalTrackGroup.opponentVolume = volume; menubarLabelVolumeVocalsOpponent.text = 'Enemy - ${Std.int(event.value)}%'; }; @@ -2904,7 +2903,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState pitch = Math.floor(pitch / 0.25) * 0.25; // Round to nearest 0.25. #if FLX_PITCH if (audioInstTrack != null) audioInstTrack.pitch = pitch; - if (audioVocalTrackGroup != null) audioVocalTrackGroup.pitch = pitch; + audioVocalTrackGroup.pitch = pitch; #end var pitchDisplay:Float = Std.int(pitch * 100) / 100; // Round to 2 decimal places. menubarLabelPlaybackSpeed.text = 'Playback Speed - ${pitchDisplay}x'; @@ -3215,7 +3214,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState Conductor.instance.update(audioInstTrack.time); handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); // Resync vocals. - if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) + if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) { audioVocalTrackGroup.time = audioInstTrack.time; } @@ -3233,7 +3232,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState Conductor.instance.update(audioInstTrack.time); handleHitsounds(oldSongPosition, Conductor.instance.songPosition + Conductor.instance.instrumentalOffset); // Resync vocals. - if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) + if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100) { audioVocalTrackGroup.time = audioInstTrack.time; } @@ -5321,7 +5320,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { FlxG.sound.music = audioInstTrack; } - if (audioVocalTrackGroup != null) targetState.vocals = audioVocalTrackGroup; + targetState.vocals = audioVocalTrackGroup; this.persistentUpdate = false; this.persistentDraw = false; @@ -5433,7 +5432,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState if (audioInstTrack != null) { audioInstTrack.play(false, audioInstTrack.time); - if (audioVocalTrackGroup != null) audioVocalTrackGroup.play(false, audioInstTrack.time); + audioVocalTrackGroup.play(false, audioInstTrack.time); } playbarPlay.text = '||'; // Pause @@ -5671,7 +5670,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState audioInstTrack.time = scrollPositionInMs + playheadPositionInMs - Conductor.instance.instrumentalOffset; // Update the songPosition in the Conductor. Conductor.instance.update(audioInstTrack.time); - if (audioVocalTrackGroup != null) audioVocalTrackGroup.time = audioInstTrack.time; + audioVocalTrackGroup.time = audioInstTrack.time; } // We need to update the note sprites because we changed the scroll position. @@ -5892,7 +5891,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState function stopAudioPlayback():Void { if (audioInstTrack != null) audioInstTrack.pause(); - if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause(); + audioVocalTrackGroup.pause(); playbarPlay.text = '>'; } @@ -5927,7 +5926,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Keep the track at the end. audioInstTrack.time = audioInstTrack.length; } - if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause(); + audioVocalTrackGroup.pause(); }; } else @@ -5941,12 +5940,22 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState healthIconsDirty = true; } + function hardRefreshOffsetsToolbox():Void + { + var offsetsToolbox:ChartEditorOffsetsToolbox = cast this.getToolbox(CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT); + if (offsetsToolbox != null) + { + offsetsToolbox.refreshAudioPreview(); + offsetsToolbox.refresh(); + } + } + /** * Clear the voices group. */ public function clearVocals():Void { - if (audioVocalTrackGroup != null) audioVocalTrackGroup.clear(); + audioVocalTrackGroup.clear(); } function isNoteSelected(note:Null):Bool @@ -5971,7 +5980,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState // Stop the music. if (welcomeMusic != null) welcomeMusic.destroy(); if (audioInstTrack != null) audioInstTrack.destroy(); - if (audioVocalTrackGroup != null) audioVocalTrackGroup.destroy(); + audioVocalTrackGroup.destroy(); } function applyCanQuickSave():Void diff --git a/source/funkin/ui/debug/charting/commands/SetAudioOffsetCommand.hx b/source/funkin/ui/debug/charting/commands/SetAudioOffsetCommand.hx new file mode 100644 index 000000000..aef402244 --- /dev/null +++ b/source/funkin/ui/debug/charting/commands/SetAudioOffsetCommand.hx @@ -0,0 +1,109 @@ +package funkin.ui.debug.charting.commands; + +import funkin.data.song.SongData.SongNoteData; +import funkin.data.song.SongData.SongEventData; +import funkin.data.song.SongDataUtils; +import flixel.tweens.FlxEase; +import flixel.tweens.FlxTween; + +/** + * Command that copies a given set of notes and song events to the clipboard, + * without deleting them from the chart editor. + */ +@:nullSafety +@:access(funkin.ui.debug.charting.ChartEditorState) +class SetAudioOffsetCommand implements ChartEditorCommand +{ + var type:AudioOffsetType; + var oldOffset:Float = 0; + var newOffset:Float; + var refreshOffsetsToolbox:Bool; + + public function new(type:AudioOffsetType, newOffset:Float, refreshOffsetsToolbox:Bool = true) + { + this.type = type; + this.newOffset = newOffset; + this.refreshOffsetsToolbox = refreshOffsetsToolbox; + } + + public function execute(state:ChartEditorState):Void + { + switch (type) + { + case INSTRUMENTAL: + oldOffset = state.currentInstrumentalOffset; + state.currentInstrumentalOffset = newOffset; + + // Update rendering. + Conductor.instance.instrumentalOffset = state.currentInstrumentalOffset; + state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instance.instrumentalOffset; + case PLAYER: + oldOffset = state.currentVocalOffsetPlayer; + state.currentVocalOffsetPlayer = newOffset; + + // Update rendering. + state.audioVocalTrackGroup.playerVoicesOffset = state.currentVocalOffsetPlayer; + case OPPONENT: + oldOffset = state.currentVocalOffsetOpponent; + state.currentVocalOffsetOpponent = newOffset; + + // Update rendering. + state.audioVocalTrackGroup.opponentVoicesOffset = state.currentVocalOffsetOpponent; + } + + // Update the offsets toolbox. + if (refreshOffsetsToolbox) state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT); + } + + public function undo(state:ChartEditorState):Void + { + switch (type) + { + case INSTRUMENTAL: + state.currentInstrumentalOffset = oldOffset; + + // Update rendering. + Conductor.instance.instrumentalOffset = state.currentInstrumentalOffset; + state.songLengthInMs = (state.audioInstTrack?.length ?? 1000.0) + Conductor.instance.instrumentalOffset; + case PLAYER: + state.currentVocalOffsetPlayer = oldOffset; + + // Update rendering. + state.audioVocalTrackGroup.playerVoicesOffset = state.currentVocalOffsetPlayer; + case OPPONENT: + state.currentVocalOffsetOpponent = oldOffset; + + // Update rendering. + state.audioVocalTrackGroup.opponentVoicesOffset = state.currentVocalOffsetOpponent; + } + + // Update the offsets toolbox. + state.refreshToolbox(ChartEditorState.CHART_EDITOR_TOOLBOX_OFFSETS_LAYOUT); + } + + public function shouldAddToHistory(state:ChartEditorState):Bool + { + // This command is undoable. Add to the history if we actually performed an action. + return (newOffset != oldOffset); + } + + public function toString():String + { + switch (type) + { + case INSTRUMENTAL: + return 'Set Inst. Audio Offset to $newOffset'; + case PLAYER: + return 'Set Player Audio Offset to $newOffset'; + case OPPONENT: + return 'Set Opponent Audio Offset to $newOffset'; + } + } +} + +enum AudioOffsetType +{ + INSTRUMENTAL; + PLAYER; + OPPONENT; +} diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx index 7f0a1e155..8e40cfc42 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx @@ -137,6 +137,8 @@ class ChartEditorAudioHandler result = playVocals(state, DAD, opponentId, instId); // if (!result) return false; + state.hardRefreshOffsetsToolbox(); + return true; } @@ -244,10 +246,7 @@ class ChartEditorAudioHandler public static function stopExistingVocals(state:ChartEditorState):Void { - if (state.audioVocalTrackGroup != null) - { - state.audioVocalTrackGroup.clear(); - } + state.audioVocalTrackGroup.clear(); if (state.audioWaveforms != null) { state.audioWaveforms.clear(); diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx index 9c86269e8..04d89e3f4 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx @@ -132,11 +132,8 @@ class ChartEditorImportExportHandler state.audioInstTrack.stop(); state.audioInstTrack = null; } - if (state.audioVocalTrackGroup != null) - { - state.audioVocalTrackGroup.stop(); - state.audioVocalTrackGroup.clear(); - } + state.audioVocalTrackGroup.stop(); + state.audioVocalTrackGroup.clear(); } /** diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx index 9479aa840..b1af0ce4c 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorThemeHandler.hx @@ -306,10 +306,11 @@ class ChartEditorThemeHandler // Draw the major ticks. var leftTickX:Float = 0; var middleTickX:Float = state.offsetTickBitmap.width / 2 - (majorTickWidth / 2); - var rightTickX:Float = state.offsetTickBitmap.width - majorTickWidth; - state.offsetTickBitmap.fillRect(new Rectangle(leftTickX, 0, majorTickWidth / 2, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(middleTickX, 0, majorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(rightTickX, 0, majorTickWidth / 2, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + var rightTickX:Float = state.offsetTickBitmap.width - (majorTickWidth / 2); + var majorTickLength:Float = state.offsetTickBitmap.height; + state.offsetTickBitmap.fillRect(new Rectangle(leftTickX, 0, majorTickWidth / 2, majorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(middleTickX, 0, majorTickWidth, majorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(rightTickX, 0, majorTickWidth / 2, majorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); // Draw the minor ticks. var minorTick2X:Float = state.offsetTickBitmap.width * 1 / 10 - (minorTickWidth / 2); @@ -320,14 +321,15 @@ class ChartEditorThemeHandler var minorTick8X:Float = state.offsetTickBitmap.width * 7 / 10 - (minorTickWidth / 2); var minorTick9X:Float = state.offsetTickBitmap.width * 8 / 10 - (minorTickWidth / 2); var minorTick10X:Float = state.offsetTickBitmap.width * 9 / 10 - (minorTickWidth / 2); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick2X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick3X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick4X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick5X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick7X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick8X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick9X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); - state.offsetTickBitmap.fillRect(new Rectangle(minorTick10X, 0, minorTickWidth, state.offsetTickBitmap.height), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + var minorTickLength:Float = state.offsetTickBitmap.height * 1 / 3; + state.offsetTickBitmap.fillRect(new Rectangle(minorTick2X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick3X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick4X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick5X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick7X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick8X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick9X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); + state.offsetTickBitmap.fillRect(new Rectangle(minorTick10X, 0, minorTickWidth, minorTickLength), GRID_MEASURE_DIVIDER_COLOR_LIGHT); // Draw the offset ticks. // var ticksWidth:Int = Std.int(ChartEditorState.GRID_SIZE * TOTAL_COLUMN_COUNT); // 1 grid squares wide. diff --git a/source/funkin/ui/debug/charting/toolboxes/ChartEditorOffsetsToolbox.hx b/source/funkin/ui/debug/charting/toolboxes/ChartEditorOffsetsToolbox.hx index c72c7fd9a..5b26419b2 100644 --- a/source/funkin/ui/debug/charting/toolboxes/ChartEditorOffsetsToolbox.hx +++ b/source/funkin/ui/debug/charting/toolboxes/ChartEditorOffsetsToolbox.hx @@ -4,11 +4,16 @@ import funkin.audio.SoundGroup; import haxe.ui.components.Button; import haxe.ui.components.HorizontalSlider; import haxe.ui.components.Label; +import flixel.addons.display.FlxTiledSprite; +import flixel.math.FlxMath; import haxe.ui.components.NumberStepper; import haxe.ui.components.Slider; +import haxe.ui.backend.flixel.components.SpriteWrapper; +import funkin.ui.debug.charting.commands.SetAudioOffsetCommand; import funkin.ui.haxeui.components.WaveformPlayer; import funkin.audio.waveform.WaveformDataParser; import haxe.ui.containers.VBox; +import haxe.ui.containers.Absolute; import haxe.ui.containers.ScrollView; import haxe.ui.containers.Frame; import haxe.ui.core.Screen; @@ -25,7 +30,7 @@ import haxe.ui.events.UIEvent; @:build(haxe.ui.ComponentBuilder.build("assets/exclude/data/ui/chart-editor/toolboxes/offsets.xml")) class ChartEditorOffsetsToolbox extends ChartEditorBaseToolbox { - var waveformContainer:VBox; + var waveformContainer:Absolute; var waveformScrollview:ScrollView; var waveformPlayer:WaveformPlayer; var waveformOpponent:WaveformPlayer; @@ -38,15 +43,56 @@ class ChartEditorOffsetsToolbox extends ChartEditorBaseToolbox var offsetStepperPlayer:NumberStepper; var offsetStepperOpponent:NumberStepper; var offsetStepperInstrumental:NumberStepper; + var offsetTicksContainer:Absolute; + var playheadSprite:SpriteWrapper; + + static final TICK_LABEL_X_OFFSET:Float = 4.0; + + static final PLAYHEAD_RIGHT_PAD:Float = 10.0; static final BASE_SCALE:Float = 64.0; static final MIN_SCALE:Float = 4.0; static final WAVEFORM_ZOOM_MULT:Float = 1.5; + static final MAGIC_SCALE_BASE_TIME:Float = 5.0; + var waveformScale:Float = BASE_SCALE; + var playheadAbsolutePos(get, set):Float; + + function get_playheadAbsolutePos():Float + { + return playheadSprite.left; + } + + function set_playheadAbsolutePos(value:Float):Float + { + return playheadSprite.left = value; + } + + var playheadRelativePos(get, set):Float; + + function get_playheadRelativePos():Float + { + return playheadSprite.left - waveformScrollview.hscrollPos; + } + + function set_playheadRelativePos(value:Float):Float + { + return playheadSprite.left = waveformScrollview.hscrollPos + value; + } + + /** + * The amount you need to multiply the zoom by such that, at the base zoom level, one tick is equal to `MAGIC_SCALE_BASE_TIME` seconds. + */ + var waveformMagicFactor:Float = 1.0; + var audioPreviewTracks:SoundGroup; + var tickTiledSprite:FlxTiledSprite; + + var tickLabels:Array