2024-02-09 14:58:57 -05:00
package funkin . ui . debug . charting . toolboxes ;
2024-03-02 23:49:27 -05:00
import flixel . addons . display . FlxTiledSprite ;
import flixel . math . FlxMath ;
2024-02-09 14:58:57 -05:00
import funkin . audio . SoundGroup ;
2024-03-02 23:49:27 -05:00
import funkin . audio . waveform . WaveformDataParser ;
import funkin . ui . debug . charting . commands . SetFreeplayPreviewCommand ;
import funkin . ui . haxeui . components . WaveformPlayer ;
import funkin . ui . freeplay . FreeplayState ;
2024-03-13 21:47:15 -04:00
import funkin . util . TimerUtil ;
2024-03-02 23:49:27 -05:00
import haxe . ui . backend . flixel . components . SpriteWrapper ;
2024-02-09 14:58:57 -05:00
import haxe . ui . components . Button ;
import haxe . ui . components . HorizontalSlider ;
import haxe . ui . components . Label ;
import haxe . ui . components . NumberStepper ;
import haxe . ui . components . Slider ;
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 ;
import haxe . ui . events . DragEvent ;
import haxe . ui . events . MouseEvent ;
import haxe . ui . events . UIEvent ;
/ * *
* The toolbox which allows modifying information like Song Title , Scroll Speed , Characters / Stages , and starting BPM .
* /
// @:nullSafety // TODO: Fix null safety when used with HaxeUI build macros.
@ : access ( funkin . ui . debug . charting . ChartEditorState )
@ : build ( haxe . ui . ComponentBuilder . build ( " a s s e t s / e x c l u d e / d a t a / u i / c h a r t - e d i t o r / t o o l b o x e s / f r e e p l a y . x m l " ) )
class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
{
var waveformContainer: Absolute ;
var waveformScrollview: ScrollView ;
var waveformMusic: WaveformPlayer ;
var freeplayButtonZoomIn: Button ;
var freeplayButtonZoomOut: Button ;
var freeplayButtonPause: Button ;
var freeplayButtonPlay: Button ;
var freeplayButtonStop: Button ;
var freeplayPreviewStart: NumberStepper ;
var freeplayPreviewEnd: NumberStepper ;
var freeplayTicksContainer: Absolute ;
var playheadSprite: SpriteWrapper ;
var previewSelectionSprite: 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 STARTING_SCALE : Float = 1024.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 = STARTING_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 ;
}
var previewBoxStartPosAbsolute( get , set ) : Float ;
function get_previewBoxStartPosAbsolute ( ) : Float
{
return previewSelectionSprite . left ;
}
function set_previewBoxStartPosAbsolute ( value : Float ) : Float
{
return previewSelectionSprite . left = value ;
}
var previewBoxEndPosAbsolute( get , set ) : Float ;
function get_previewBoxEndPosAbsolute ( ) : Float
{
return previewSelectionSprite . left + previewSelectionSprite . width ;
}
function set_previewBoxEndPosAbsolute ( value : Float ) : Float
{
if ( value < previewBoxStartPosAbsolute ) return previewSelectionSprite . left = previewBoxStartPosAbsolute ;
return previewSelectionSprite . width = value - previewBoxStartPosAbsolute ;
}
var previewBoxStartPosRelative( get , set ) : Float ;
function get_previewBoxStartPosRelative ( ) : Float
{
return previewSelectionSprite . left - waveformScrollview . hscrollPos ;
}
function set_previewBoxStartPosRelative ( value : Float ) : Float
{
return previewSelectionSprite . left = waveformScrollview . hscrollPos + value ;
}
var previewBoxEndPosRelative( get , set ) : Float ;
function get_previewBoxEndPosRelative ( ) : Float
{
return previewSelectionSprite . left + previewSelectionSprite . width - waveformScrollview . hscrollPos ;
}
function set_previewBoxEndPosRelative ( value : Float ) : Float
{
if ( value < previewBoxStartPosRelative ) return previewSelectionSprite . left = previewBoxStartPosRelative ;
return previewSelectionSprite . width = value - previewBoxStartPosRelative ;
}
/ * *
* 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 freeplayPreviewVolume( get , null ) : Float ;
function get_freeplayPreviewVolume ( ) : Float
{
return freeplayMusicVolume . value * 2 / 100 ;
}
var tickLabels: Array < Label > = [ ] ;
public function n e w ( chartEditorState2 : ChartEditorState )
{
super ( chartEditorState2 ) ;
initialize ( ) ;
this . onDialogClosed = onClose ;
}
function onClose ( event : UIEvent )
{
chartEditorState . menubarItemToggleToolboxFreeplay . selected = false ;
}
function initialize ( ) : Void
{
// Starting position.
// TODO: Save and load this.
this . x = 150 ;
this . y = 250 ;
freeplayMusicVolume . onChange = ( _ ) - > {
setTrackVolume ( freeplayPreviewVolume ) ;
} ;
freeplayMusicMute . onClick = ( _ ) - > {
toggleMuteTrack ( ) ;
} ;
freeplayButtonZoomIn . onClick = ( _ ) - > {
zoomWaveformIn ( ) ;
} ;
freeplayButtonZoomOut . onClick = ( _ ) - > {
zoomWaveformOut ( ) ;
} ;
freeplayButtonPause . onClick = ( _ ) - > {
pauseAudioPreview ( ) ;
} ;
freeplayButtonPlay . onClick = ( _ ) - > {
playAudioPreview ( ) ;
} ;
freeplayButtonStop . onClick = ( _ ) - > {
stopAudioPreview ( ) ;
} ;
testPreview . onClick = ( _ ) - > {
performPreview ( ) ;
} ;
freeplayPreviewStart . onChange = ( event : UIEvent ) - > {
if ( event . value == chartEditorState . currentSongFreeplayPreviewStart ) return ;
if ( waveformDragStartPos != null ) return ; // The values are changing because we are dragging the preview.
chartEditorState . performCommand ( new SetFreeplayPreviewCommand ( event . value , null ) ) ;
refresh ( ) ;
}
freeplayPreviewEnd . onChange = ( event : UIEvent ) - > {
if ( event . value == chartEditorState . currentSongFreeplayPreviewEnd ) return ;
if ( waveformDragStartPos != null ) return ; // The values are changing because we are dragging the preview.
chartEditorState . performCommand ( new SetFreeplayPreviewCommand ( null , event . value ) ) ;
refresh ( ) ;
}
waveformScrollview . onScroll = ( _ ) - > {
if ( ! audioPreviewTracks . playing )
{
// Move the playhead if it would go out of view.
var prevPlayheadRelativePos = playheadRelativePos ;
playheadRelativePos = FlxMath . bound ( playheadRelativePos , 0 , waveformScrollview . width - PLAYHEAD_RIGHT_PAD ) ;
trace ( ' n e w P o s : ${ playheadRelativePos } ' ) ;
var diff = playheadRelativePos - prevPlayheadRelativePos ;
if ( diff != 0 )
{
// We have to change the song time to match the playhead position when we move it.
var currentWaveformIndex: Int = Std . int ( playheadAbsolutePos * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var targetSongTimeSeconds: Float = waveformMusic . waveform . waveformData . indexToSeconds ( currentWaveformIndex ) ;
audioPreviewTracks . time = targetSongTimeSeconds * Constants . MS_PER_SEC ;
}
addOffsetsToAudioPreview ( ) ;
}
e lse
{
// The scrollview probably changed because the song position changed.
// If we try to move the song now it will glitch.
}
// Either way, clipRect has changed, so we need to refresh the waveforms.
refresh ( ) ;
} ;
initializeTicks ( ) ;
refreshAudioPreview ( ) ;
refresh ( ) ;
refreshTicks ( ) ;
waveformMusic . registerEvent ( MouseEvent . MOUSE_DOWN , ( _ ) - > {
onStartDragWaveform ( ) ;
} ) ;
freeplayTicksContainer . registerEvent ( MouseEvent . MOUSE_DOWN , ( _ ) - > {
onStartDragPlayhead ( ) ;
} ) ;
}
function initializeTicks ( ) : Void
{
tickTiledSprite = new FlxTiledSprite ( chartEditorState . offsetTickBitmap , 100 , chartEditorState . offsetTickBitmap . height , true , false ) ;
freeplayTicksSprite . sprite = tickTiledSprite ;
tickTiledSprite . width = 5000 ;
}
/ * *
* Pull the audio tracks from the chart editor state and create copies of them to play in the Offsets Toolbox .
* These must be DEEP CLONES or e lse the editor will affect the audio preview !
* /
public function refreshAudioPreview ( ) : Void
{
if ( audioPreviewTracks == null )
{
audioPreviewTracks = new SoundGroup ( ) ;
// Make sure audioPreviewTracks (and all its children) receives update() calls.
chartEditorState . add ( audioPreviewTracks ) ;
}
e lse
{
audioPreviewTracks . stop ( ) ;
audioPreviewTracks . clear ( ) ;
}
var instTrack = chartEditorState . audioInstTrack . clone ( ) ;
audioPreviewTracks . add ( instTrack ) ;
var playerVoice = chartEditorState . audioVocalTrackGroup . getPlayerVoice ( ) ;
if ( playerVoice != null ) audioPreviewTracks . add ( playerVoice . clone ( ) ) ;
var opponentVoice = chartEditorState . audioVocalTrackGroup . getOpponentVoice ( ) ;
if ( opponentVoice != null ) audioPreviewTracks . add ( opponentVoice . clone ( ) ) ;
// Build player waveform.
// waveformMusic.waveform.forceUpdate = true;
2024-03-13 21:47:15 -04:00
var perfStart: Float = TimerUtil . start ( ) ;
2024-02-17 02:13:11 -05:00
var waveformData1 = playerVoice ? . waveformData ;
var waveformData2 = opponentVoice ? . waveformData ? ? playerVoice ? . waveformData ; // this null check is for songs that only have 1 vocals file!
2024-02-09 14:58:57 -05:00
var waveformData3 = chartEditorState . audioInstTrack . waveformData ;
2024-02-17 02:13:11 -05:00
var waveformData = waveformData3 . merge ( waveformData1 ) . merge ( waveformData2 ) ;
2024-03-13 21:47:15 -04:00
trace ( ' W a v e f o r m d a t a m e r g i n g t o o k : ${ TimerUtil . seconds ( perfStart ) } ' ) ;
2024-02-09 14:58:57 -05:00
waveformMusic . waveform . waveformData = waveformData ;
// Set the width and duration to render the full waveform, with the clipRect applied we only render a segment of it.
waveformMusic . waveform . duration = instTrack . length / Constants . MS_PER_SEC ;
addOffsetsToAudioPreview ( ) ;
}
public function refreshTicks ( ) : Void
{
while ( tickLabels . length > 0 )
{
var label = tickLabels . pop ( ) ;
freeplayTicksContainer . removeComponent ( label ) ;
}
var labelYPos: Float = chartEditorState . offsetTickBitmap . height / 2 ;
var labelHeight: Float = chartEditorState . offsetTickBitmap . height / 2 ;
var numberOfTicks: Int = Math . floor ( waveformMusic . waveform . width / chartEditorState . offsetTickBitmap . width * 2 ) + 1 ;
for ( index in 0 ... numberOfTicks )
{
var tickPos = chartEditorState . offsetTickBitmap . width / 2 * index ;
var tickTime = tickPos * ( waveformScale / BASE_SCALE * waveformMagicFactor ) / waveformMusic . waveform . waveformData . pointsPerSecond ( ) ;
var tickLabel: Label = new Label ( ) ;
tickLabel . text = formatTime ( tickTime ) ;
tickLabel . styleNames = " o f f s e t - t i c k s - l a b e l " ;
tickLabel . height = labelHeight ;
// Positioning within offsetTicksContainer is absolute (relative to the container itself).
tickLabel . top = labelYPos ;
tickLabel . left = tickPos + TICK_LABEL_X_OFFSET ;
freeplayTicksContainer . addComponent ( tickLabel ) ;
tickLabels . push ( tickLabel ) ;
}
}
function formatTime ( seconds : Float ) : String
{
if ( seconds <= 0 ) return " 0 . 0 " ;
var integerSeconds = Math . floor ( seconds ) ;
var decimalSeconds = Math . floor ( ( seconds - integerSeconds ) * 10 ) ;
if ( integerSeconds < 60 )
{
return ' ${ integerSeconds } . ${ decimalSeconds } ' ;
}
e lse
{
var integerMinutes = Math . floor ( integerSeconds / 60 ) ;
var remainingSeconds = integerSeconds % 60 ;
var remainingSecondsPad: String = remainingSeconds < 10 ? ' 0 $ remainingSeconds ' : ' $ remainingSeconds ' ;
return ' ${ integerMinutes } : ${ remainingSecondsPad } ${ decimalSeconds > 0 ? ' . $ decimalSeconds ' : ' ' } ' ;
}
}
function buildTickLabel ( ) : Void { }
public function onStartDragPlayhead ( ) : Void
{
Screen . instance . registerEvent ( MouseEvent . MOUSE_MOVE , onDragPlayhead ) ;
Screen . instance . registerEvent ( MouseEvent . MOUSE_UP , onStopDragPlayhead ) ;
movePlayheadToMouse ( ) ;
}
public function onDragPlayhead ( event : MouseEvent ) : Void
{
movePlayheadToMouse ( ) ;
}
public function onStopDragPlayhead ( event : MouseEvent ) : Void
{
// Stop dragging.
Screen . instance . unregisterEvent ( MouseEvent . MOUSE_MOVE , onDragPlayhead ) ;
Screen . instance . unregisterEvent ( MouseEvent . MOUSE_UP , onStopDragPlayhead ) ;
}
function movePlayheadToMouse ( ) : Void
{
// Determine the position of the mouse relative to the
var mouseXPos = FlxG . mouse . x ;
var relativeMouseXPos = mouseXPos - waveformScrollview . screenX ;
var targetPlayheadPos = relativeMouseXPos + waveformScrollview . hscrollPos ;
// Move the playhead to the mouse position.
playheadAbsolutePos = targetPlayheadPos ;
// Move the audio preview to the playhead position.
var currentWaveformIndex: Int = Std . int ( playheadAbsolutePos * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var targetSongTimeSeconds: Float = waveformMusic . waveform . waveformData . indexToSeconds ( currentWaveformIndex ) ;
audioPreviewTracks . time = targetSongTimeSeconds * Constants . MS_PER_SEC ;
}
var waveformDragStartPos: Null < Float > = null ;
var waveformDragPreviewStartPos: Float ;
var waveformDragPreviewEndPos: Float ;
public function onStartDragWaveform ( ) : Void
{
waveformDragStartPos = FlxG . mouse . x ;
Screen . instance . registerEvent ( MouseEvent . MOUSE_MOVE , onDragWaveform ) ;
Screen . instance . registerEvent ( MouseEvent . MOUSE_UP , onStopDragWaveform ) ;
}
public function onDragWaveform ( event : MouseEvent ) : Void
{
// Set waveformDragPreviewStartPos and waveformDragPreviewEndPos to the position the drag started and the current mouse position.
// This only affects the visuals.
var currentAbsMousePos = FlxG . mouse . x ;
var dragDiff = currentAbsMousePos - waveformDragStartPos ;
var currentRelativeMousePos = currentAbsMousePos - waveformScrollview . screenX ;
var relativeStartPos = waveformDragStartPos - waveformScrollview . screenX ;
var isDraggingRight = dragDiff > 0 ;
var hasDraggedEnough = Math . abs ( dragDiff ) > 10 ;
if ( hasDraggedEnough )
{
if ( isDraggingRight )
{
waveformDragPreviewStartPos = relativeStartPos ;
waveformDragPreviewEndPos = currentRelativeMousePos ;
}
e lse
{
waveformDragPreviewStartPos = currentRelativeMousePos ;
waveformDragPreviewEndPos = relativeStartPos ;
}
}
refresh ( ) ;
}
public function onStopDragWaveform ( event : MouseEvent ) : Void
{
Screen . instance . unregisterEvent ( MouseEvent . MOUSE_MOVE , onDragWaveform ) ;
Screen . instance . unregisterEvent ( MouseEvent . MOUSE_UP , onStopDragWaveform ) ;
var previewStartPosAbsolute = waveformDragPreviewStartPos + waveformScrollview . hscrollPos ;
var previewStartPosIndex: Int = Std . int ( previewStartPosAbsolute * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var previewStartPosMs: Int = Std . int ( waveformMusic . waveform . waveformData . indexToSeconds ( previewStartPosIndex ) * Constants . MS_PER_SEC ) ;
var previewEndPosAbsolute = waveformDragPreviewEndPos + waveformScrollview . hscrollPos ;
var previewEndPosIndex: Int = Std . int ( previewEndPosAbsolute * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var previewEndPosMs: Int = Std . int ( waveformMusic . waveform . waveformData . indexToSeconds ( previewEndPosIndex ) * Constants . MS_PER_SEC ) ;
chartEditorState . performCommand ( new SetFreeplayPreviewCommand ( previewStartPosMs , previewEndPosMs ) ) ;
waveformDragStartPos = null ;
waveformDragPreviewStartPos = 0 ;
waveformDragPreviewEndPos = 0 ;
refresh ( ) ;
addOffsetsToAudioPreview ( ) ;
}
public function playAudioPreview ( ) : Void
{
if ( isPerformingPreview ) stopPerformingPreview ( ) ;
audioPreviewTracks . volume = freeplayPreviewVolume ;
audioPreviewTracks . play ( false , audioPreviewTracks . time ) ;
}
public function addOffsetsToAudioPreview ( ) : Void
{
var trackInst = audioPreviewTracks . members [ 0 ] ;
if ( trackInst != null )
{
trackInst . time -= chartEditorState . currentInstrumentalOffset ;
}
var trackPlayer = audioPreviewTracks . members [ 1 ] ;
if ( trackPlayer != null )
{
trackPlayer . time -= chartEditorState . currentVocalOffsetPlayer ;
}
var trackOpponent = audioPreviewTracks . members [ 2 ] ;
if ( trackOpponent != null )
{
trackOpponent . time -= chartEditorState . currentVocalOffsetOpponent ;
}
}
public function pauseAudioPreview ( ) : Void
{
if ( isPerformingPreview ) stopPerformingPreview ( ) ;
audioPreviewTracks . pause ( ) ;
}
public function stopAudioPreview ( ) : Void
{
if ( isPerformingPreview ) stopPerformingPreview ( ) ;
audioPreviewTracks . stop ( ) ;
audioPreviewTracks . time = 0 ;
waveformScrollview . hscrollPos = 0 ;
playheadAbsolutePos = 0 + playheadSprite . width ;
refresh ( ) ;
addOffsetsToAudioPreview ( ) ;
}
public function zoomWaveformIn ( ) : Void
{
if ( isPerformingPreview ) stopPerformingPreview ( ) ;
if ( waveformScale > MIN_SCALE )
{
waveformScale = waveformScale / WAVEFORM_ZOOM_MULT ;
if ( waveformScale < MIN_SCALE ) waveformScale = MIN_SCALE ;
trace ( ' Z o o m i n g i n , s c a l e : ${ waveformScale } ' ) ;
// Update the playhead too!
playheadAbsolutePos = playheadAbsolutePos * WAVEFORM_ZOOM_MULT ;
// Recenter the scroll view on the playhead.
var vaguelyCenterPlayheadOffset = waveformScrollview . width / 8 ;
waveformScrollview . hscrollPos = playheadAbsolutePos - vaguelyCenterPlayheadOffset ;
refresh ( ) ;
refreshTicks ( ) ;
}
e lse
{
waveformScale = MIN_SCALE ;
}
}
public function zoomWaveformOut ( ) : Void
{
waveformScale = waveformScale * WAVEFORM_ZOOM_MULT ;
if ( waveformScale < MIN_SCALE ) waveformScale = MIN_SCALE ;
trace ( ' Z o o m i n g o u t , s c a l e : ${ waveformScale } ' ) ;
// Update the playhead too!
playheadAbsolutePos = playheadAbsolutePos / WAVEFORM_ZOOM_MULT ;
// Recenter the scroll view on the playhead.
var vaguelyCenterPlayheadOffset = waveformScrollview . width / 8 ;
waveformScrollview . hscrollPos = playheadAbsolutePos - vaguelyCenterPlayheadOffset ;
refresh ( ) ;
refreshTicks ( ) ;
}
public function setTrackVolume ( volume : Float ) : Void
{
audioPreviewTracks . volume = volume ;
}
public function muteTrack ( ) : Void
{
audioPreviewTracks . muted = true ;
}
public function unmuteTrack ( ) : Void
{
audioPreviewTracks . muted = false ;
}
public function toggleMuteTrack ( ) : Void
{
audioPreviewTracks . muted = ! audioPreviewTracks . muted ;
}
var isPerformingPreview: Bool = false ;
var isFadingOutPreview: Bool = false ;
public function performPreview ( ) : Void
{
isPerformingPreview = true ;
isFadingOutPreview = false ;
audioPreviewTracks . play ( true , chartEditorState . currentSongFreeplayPreviewStart ) ;
audioPreviewTracks . fadeIn ( FreeplayState . FADE_IN_DURATION , FreeplayState . FADE_IN_START_VOLUME * freeplayPreviewVolume ,
FreeplayState . FADE_IN_END_VOLUME * freeplayPreviewVolume , null ) ;
}
public function stopPerformingPreview ( ) : Void
{
isPerformingPreview = false ;
isFadingOutPreview = false ;
audioPreviewTracks . volume = freeplayPreviewVolume ;
audioPreviewTracks . pause ( ) ;
}
public override function update ( elapsed : Float )
{
super . update ( elapsed ) ;
if ( isPerformingPreview && ! audioPreviewTracks . playing )
{
stopPerformingPreview ( ) ;
}
if ( isPerformingPreview && audioPreviewTracks . playing )
{
var startFadeOutTime = chartEditorState . currentSongFreeplayPreviewEnd - ( FreeplayState . FADE_OUT_DURATION * Constants . MS_PER_SEC ) ;
trace ( ' s t a r t F a d e O u t T i m e : ${ audioPreviewTracks . time } > = ${ startFadeOutTime } ' ) ;
if ( ! isFadingOutPreview && audioPreviewTracks . time >= startFadeOutTime )
{
isFadingOutPreview = true ;
audioPreviewTracks . fadeOut ( FreeplayState . FADE_OUT_DURATION , FreeplayState . FADE_OUT_END_VOLUME * freeplayPreviewVolume , ( _ ) - > {
trace ( ' S t o p p e r f o r m i n g p r e v i e w ! ${ audioPreviewTracks . time } ' ) ;
stopPerformingPreview ( ) ;
} ) ;
}
}
if ( audioPreviewTracks . playing )
{
var targetScrollPos: Float = waveformMusic . waveform . waveformData . secondsToIndex ( audioPreviewTracks . time / Constants . MS_PER_SEC ) / ( waveformScale / BASE_SCALE * waveformMagicFactor ) ;
// waveformScrollview.hscrollPos = targetScrollPos;
var prevPlayheadAbsolutePos = playheadAbsolutePos ;
playheadAbsolutePos = targetScrollPos ;
var playheadDiff = playheadAbsolutePos - prevPlayheadAbsolutePos ;
// BEHAVIOR C.
// Copy Audacity!
// If the playhead is out of view, jump forward or backward by one screen width until it's in view.
if ( playheadAbsolutePos < waveformScrollview . hscrollPos )
{
waveformScrollview . hscrollPos -= waveformScrollview . width ;
}
if ( playheadAbsolutePos > waveformScrollview . hscrollPos + waveformScrollview . width )
{
waveformScrollview . hscrollPos += waveformScrollview . width ;
}
}
freeplayLabelTime . text = formatTime ( audioPreviewTracks . time / Constants . MS_PER_SEC ) ;
if ( waveformDragStartPos != null && ( waveformDragPreviewStartPos > 0 && waveformDragPreviewEndPos > 0 ) )
{
var previewStartPosAbsolute = waveformDragPreviewStartPos + waveformScrollview . hscrollPos ;
var previewStartPosIndex: Int = Std . int ( previewStartPosAbsolute * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var previewStartPosMs: Int = Std . int ( waveformMusic . waveform . waveformData . indexToSeconds ( previewStartPosIndex ) * Constants . MS_PER_SEC ) ;
var previewEndPosAbsolute = waveformDragPreviewEndPos + waveformScrollview . hscrollPos ;
var previewEndPosIndex: Int = Std . int ( previewEndPosAbsolute * ( waveformScale / BASE_SCALE * waveformMagicFactor ) ) ;
var previewEndPosMs: Int = Std . int ( waveformMusic . waveform . waveformData . indexToSeconds ( previewEndPosIndex ) * Constants . MS_PER_SEC ) ;
// Set the values in milliseconds.
freeplayPreviewStart . value = previewStartPosMs ;
freeplayPreviewEnd . value = previewEndPosMs ;
previewBoxStartPosAbsolute = previewStartPosAbsolute ;
previewBoxEndPosAbsolute = previewEndPosAbsolute ;
}
e lse
{
previewBoxStartPosAbsolute = waveformMusic . waveform . waveformData . secondsToIndex ( chartEditorState . currentSongFreeplayPreviewStart / Constants . MS_PER_SEC ) / ( waveformScale / BASE_SCALE * waveformMagicFactor ) ;
previewBoxEndPosAbsolute = waveformMusic . waveform . waveformData . secondsToIndex ( chartEditorState . currentSongFreeplayPreviewEnd / Constants . MS_PER_SEC ) / ( waveformScale / BASE_SCALE * waveformMagicFactor ) ;
freeplayPreviewStart . value = chartEditorState . currentSongFreeplayPreviewStart ;
freeplayPreviewEnd . value = chartEditorState . currentSongFreeplayPreviewEnd ;
}
}
public override function refresh ( ) : Void
{
super . refresh ( ) ;
waveformMagicFactor = MAGIC_SCALE_BASE_TIME / ( chartEditorState . offsetTickBitmap . width / waveformMusic . waveform . waveformData . pointsPerSecond ( ) ) ;
var currentZoomFactor = waveformScale / BASE_SCALE * waveformMagicFactor ;
var maxWidth: Int = - 1 ;
waveformMusic . waveform . time = - chartEditorState . currentInstrumentalOffset / Constants . MS_PER_SEC ;
waveformMusic . waveform . width = ( waveformMusic . waveform . waveformData ? . length ? ? 1000 ) / c u r r e n t Z o o m F a c t o r ;
if ( waveformMusic . waveform . width > maxWidth ) maxWidth = Std . int ( waveformMusic . waveform . width ) ;
waveformMusic . waveform . height = 65 ;
waveformMusic . waveform . markDirty ( ) ;
waveformContainer . width = maxWidth ;
tickTiledSprite . width = maxWidth ;
}
public static function build ( chartEditorState : ChartEditorState ) : ChartEditorFreeplayToolbox
{
return new ChartEditorFreeplayToolbox ( chartEditorState ) ;
}
}