mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-21 17:39:20 +00:00
Work in progress on offsets in Chart Editor state.
This commit is contained in:
parent
e23c1464f6
commit
7f0caeb026
|
@ -45,8 +45,6 @@ class Conductor
|
|||
*/
|
||||
public static var songPosition(default, null):Float = 0;
|
||||
|
||||
public static var songPositionNoOffset(default, null):Float = 0;
|
||||
|
||||
/**
|
||||
* Beats per minute of the current song at the current time.
|
||||
*/
|
||||
|
@ -61,6 +59,21 @@ class Conductor
|
|||
return currentTimeChange.bpm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Beats per minute of the current song at the start time.
|
||||
*/
|
||||
public static var startingBPM(get, never):Float;
|
||||
|
||||
static function get_startingBPM():Float
|
||||
{
|
||||
if (bpmOverride != null) return bpmOverride;
|
||||
|
||||
var timeChange = timeChanges[0];
|
||||
if (timeChange == null) return Constants.DEFAULT_BPM;
|
||||
|
||||
return timeChange.bpm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current value set by `forceBPM`.
|
||||
* If false, BPM is determined by time changes.
|
||||
|
@ -146,18 +159,23 @@ class Conductor
|
|||
*/
|
||||
public static var currentStepTime(default, null):Float;
|
||||
|
||||
public static var currentStepTimeNoOffset(default, null):Float;
|
||||
|
||||
public static var beatHit(default, null):FlxSignal = new FlxSignal();
|
||||
public static var stepHit(default, null):FlxSignal = new FlxSignal();
|
||||
|
||||
public static var lastSongPos:Float;
|
||||
|
||||
/**
|
||||
* An offset tied to the current chart file to compensate for a delay in the instrumental.
|
||||
*/
|
||||
public static var instrumentalOffset:Float = 0;
|
||||
|
||||
/**
|
||||
* The instrumental offset, in terms of steps.
|
||||
*/
|
||||
public static var instrumentalOffsetSteps(get, never):Float;
|
||||
|
||||
static function get_instrumentalOffsetSteps():Float
|
||||
{
|
||||
var startingStepLengthMs:Float = ((Constants.SECS_PER_MIN / startingBPM) * Constants.MS_PER_SEC) / timeSignatureNumerator;
|
||||
|
||||
return instrumentalOffset / startingStepLengthMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* An offset tied to the file format of the audio file being played.
|
||||
*/
|
||||
|
@ -168,6 +186,9 @@ class Conductor
|
|||
*/
|
||||
public static var inputOffset:Float = 0;
|
||||
|
||||
/**
|
||||
* The number of beats in a measure. May be fractional depending on the time signature.
|
||||
*/
|
||||
public static var beatsPerMeasure(get, never):Float;
|
||||
|
||||
static function get_beatsPerMeasure():Float
|
||||
|
@ -176,6 +197,10 @@ class Conductor
|
|||
return stepsPerMeasure / Constants.STEPS_PER_BEAT;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of steps in a measure.
|
||||
* TODO: I don't think this can be fractional?
|
||||
*/
|
||||
public static var stepsPerMeasure(get, never):Int;
|
||||
|
||||
static function get_stepsPerMeasure():Int
|
||||
|
@ -184,6 +209,21 @@ class Conductor
|
|||
return Std.int(timeSignatureNumerator / timeSignatureDenominator * Constants.STEPS_PER_BEAT * Constants.STEPS_PER_BEAT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal fired when the Conductor advances to a new measure.
|
||||
*/
|
||||
public static var measureHit(default, null):FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Signal fired when the Conductor advances to a new beat.
|
||||
*/
|
||||
public static var beatHit(default, null):FlxSignal = new FlxSignal();
|
||||
|
||||
/**
|
||||
* Signal fired when the Conductor advances to a new step.
|
||||
*/
|
||||
public static var stepHit(default, null):FlxSignal = new FlxSignal();
|
||||
|
||||
function new() {}
|
||||
|
||||
/**
|
||||
|
@ -224,29 +264,29 @@ class Conductor
|
|||
songPosition = (FlxG.sound.music != null) ? (FlxG.sound.music.time + instrumentalOffset + formatOffset) : 0.0;
|
||||
}
|
||||
|
||||
var oldMeasure = currentMeasure;
|
||||
var oldBeat = currentBeat;
|
||||
var oldStep = currentStep;
|
||||
|
||||
// Set the song position we are at (for purposes of calculating note positions, etc).
|
||||
Conductor.songPosition = songPosition;
|
||||
|
||||
// Exclude the offsets we just included earlier.
|
||||
// This is the "true" song position that the audio should be using.
|
||||
Conductor.songPositionNoOffset = Conductor.songPosition - instrumentalOffset - formatOffset;
|
||||
|
||||
currentTimeChange = timeChanges[0];
|
||||
for (i in 0...timeChanges.length)
|
||||
if (Conductor.songPosition > 0.0)
|
||||
{
|
||||
if (songPosition >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i];
|
||||
for (i in 0...timeChanges.length)
|
||||
{
|
||||
if (songPosition >= timeChanges[i].timeStamp) currentTimeChange = timeChanges[i];
|
||||
|
||||
if (songPosition < timeChanges[i].timeStamp) break;
|
||||
if (songPosition < timeChanges[i].timeStamp) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTimeChange == null && bpmOverride == null && FlxG.sound.music != null)
|
||||
{
|
||||
trace('WARNING: Conductor is broken, timeChanges is empty.');
|
||||
}
|
||||
else if (currentTimeChange != null)
|
||||
else if (currentTimeChange != null && Conductor.songPosition > 0.0)
|
||||
{
|
||||
// roundDecimal prevents representing 8 as 7.9999999
|
||||
currentStepTime = FlxMath.roundDecimal((currentTimeChange.beatTime * 4) + (songPosition - currentTimeChange.timeStamp) / stepLengthMs, 6);
|
||||
|
@ -255,9 +295,6 @@ class Conductor
|
|||
currentStep = Math.floor(currentStepTime);
|
||||
currentBeat = Math.floor(currentBeatTime);
|
||||
currentMeasure = Math.floor(currentMeasureTime);
|
||||
|
||||
currentStepTimeNoOffset = FlxMath.roundDecimal((currentTimeChange.beatTime * 4)
|
||||
+ (songPositionNoOffset - currentTimeChange.timeStamp) / stepLengthMs, 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -268,8 +305,6 @@ class Conductor
|
|||
currentStep = Math.floor(currentStepTime);
|
||||
currentBeat = Math.floor(currentBeatTime);
|
||||
currentMeasure = Math.floor(currentMeasureTime);
|
||||
|
||||
currentStepTimeNoOffset = FlxMath.roundDecimal((songPositionNoOffset / stepLengthMs), 4);
|
||||
}
|
||||
|
||||
// FlxSignals are really cool.
|
||||
|
@ -282,6 +317,11 @@ class Conductor
|
|||
{
|
||||
beatHit.dispatch();
|
||||
}
|
||||
|
||||
if (currentMeasure != oldMeasure)
|
||||
{
|
||||
measureHit.dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
public static function mapTimeChanges(songTimeChanges:Array<SongTimeChange>)
|
||||
|
|
|
@ -796,15 +796,6 @@ class PlayState extends MusicBeatSubState
|
|||
}
|
||||
|
||||
Conductor.update(); // Normal conductor update.
|
||||
|
||||
if (!isGamePaused)
|
||||
{
|
||||
// Interpolation type beat
|
||||
if (Conductor.lastSongPos != Conductor.songPosition)
|
||||
{
|
||||
Conductor.lastSongPos = Conductor.songPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var androidPause:Bool = false;
|
||||
|
@ -1171,12 +1162,12 @@ class PlayState extends MusicBeatSubState
|
|||
|
||||
if (!startingSong
|
||||
&& FlxG.sound.music != null
|
||||
&& (Math.abs(FlxG.sound.music.time - (Conductor.songPositionNoOffset)) > 200
|
||||
|| Math.abs(vocals.checkSyncError(Conductor.songPositionNoOffset)) > 200))
|
||||
&& (Math.abs(FlxG.sound.music.time - (Conductor.songPosition + Conductor.instrumentalOffset)) > 200
|
||||
|| Math.abs(vocals.checkSyncError(Conductor.songPosition + Conductor.instrumentalOffset)) > 200))
|
||||
{
|
||||
trace("VOCALS NEED RESYNC");
|
||||
if (vocals != null) trace(vocals.checkSyncError(Conductor.songPositionNoOffset));
|
||||
trace(FlxG.sound.music.time - (Conductor.songPositionNoOffset));
|
||||
if (vocals != null) trace(vocals.checkSyncError(Conductor.songPosition + Conductor.instrumentalOffset));
|
||||
trace(FlxG.sound.music.time - (Conductor.songPosition + Conductor.instrumentalOffset));
|
||||
resyncVocals();
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ class MusicBeatState extends FlxTransitionableState implements IEventHandler
|
|||
{
|
||||
// Display Conductor info in the watch window.
|
||||
FlxG.watch.addQuick("songPosition", Conductor.songPosition);
|
||||
FlxG.watch.addQuick("songPositionNoOffset", Conductor.songPosition + Conductor.instrumentalOffset);
|
||||
FlxG.watch.addQuick("musicTime", FlxG.sound.music?.time ?? 0.0);
|
||||
FlxG.watch.addQuick("bpm", Conductor.bpm);
|
||||
FlxG.watch.addQuick("currentMeasureTime", Conductor.currentBeatTime);
|
||||
|
|
|
@ -23,12 +23,14 @@ import flixel.util.FlxSort;
|
|||
import flixel.util.FlxTimer;
|
||||
import funkin.audio.visualize.PolygonSpectogram;
|
||||
import funkin.audio.VoicesGroup;
|
||||
import funkin.audio.FunkinSound;
|
||||
import funkin.data.notestyle.NoteStyleRegistry;
|
||||
import funkin.data.song.SongData.SongCharacterData;
|
||||
import funkin.data.song.SongData.SongChartData;
|
||||
import funkin.data.song.SongData.SongEventData;
|
||||
import funkin.data.song.SongData.SongMetadata;
|
||||
import funkin.data.song.SongData.SongNoteData;
|
||||
import funkin.data.song.SongData.SongOffsets;
|
||||
import funkin.data.song.SongDataUtils;
|
||||
import funkin.data.song.SongRegistry;
|
||||
import funkin.input.Cursor;
|
||||
|
@ -245,6 +247,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
// Make sure playhead doesn't go outside the song.
|
||||
if (playheadPositionInMs > songLengthInMs) playheadPositionInMs = songLengthInMs;
|
||||
|
||||
onSongLengthChanged();
|
||||
|
||||
return this.songLengthInMs;
|
||||
}
|
||||
|
||||
|
@ -884,7 +888,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
* Replaced when switching instrumentals.
|
||||
* `null` until an instrumental track is loaded.
|
||||
*/
|
||||
var audioInstTrack:Null<FlxSound> = null;
|
||||
var audioInstTrack:Null<FunkinSound> = null;
|
||||
|
||||
/**
|
||||
* The raw byte data for the instrumental audio tracks.
|
||||
|
@ -1156,6 +1160,41 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
return currentSongMetadata.artist = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience property to get the song offset data for the current variation.
|
||||
*/
|
||||
var currentSongOffsets(get, set):SongOffsets;
|
||||
|
||||
function get_currentSongOffsets():SongOffsets
|
||||
{
|
||||
if (currentSongMetadata.offsets == null)
|
||||
{
|
||||
// Initialize to the default value if not set.
|
||||
currentSongMetadata.offsets = new SongOffsets();
|
||||
}
|
||||
return currentSongMetadata.offsets;
|
||||
}
|
||||
|
||||
function set_currentSongOffsets(value:SongOffsets):SongOffsets
|
||||
{
|
||||
return currentSongMetadata.offsets = value;
|
||||
}
|
||||
|
||||
var currentInstrumentalOffset(get, set):Float;
|
||||
|
||||
function get_currentInstrumentalOffset():Float
|
||||
{
|
||||
// TODO: Apply for alt instrumentals.
|
||||
return currentSongOffsets.getInstrumentalOffset();
|
||||
}
|
||||
|
||||
function set_currentInstrumentalOffset(value:Float):Float
|
||||
{
|
||||
// TODO: Apply for alt instrumentals.
|
||||
currentSongOffsets.setInstrumentalOffset(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The variation ID for the difficulty which is currently being edited.
|
||||
*/
|
||||
|
@ -2024,7 +2063,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
playbarHeadDragging = true;
|
||||
|
||||
// If we were dragging the playhead while the song was playing, resume playing.
|
||||
if (audioInstTrack != null && audioInstTrack.playing)
|
||||
if (audioInstTrack != null && audioInstTrack.isPlaying)
|
||||
{
|
||||
playbarHeadDraggingWasPlaying = true;
|
||||
stopAudioPlayback();
|
||||
|
@ -2224,8 +2263,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
menubarItemGoToBackupsFolder.onClick = _ -> this.openBackupsFolder();
|
||||
#else
|
||||
// Disable the menu item if we're not on a desktop platform.
|
||||
var menubarItemGoToBackupsFolder = findComponent('menubarItemGoToBackupsFolder', MenuItem);
|
||||
if (menubarItemGoToBackupsFolder != null) menubarItemGoToBackupsFolder.disabled = true;
|
||||
menubarItemGoToBackupsFolder.disabled = true;
|
||||
#end
|
||||
|
||||
menubarItemUserGuide.onClick = _ -> this.openUserGuideDialog();
|
||||
|
@ -2435,7 +2473,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
super.update(elapsed);
|
||||
|
||||
// These ones happen even if the modal dialog is open.
|
||||
handleMusicPlayback();
|
||||
handleMusicPlayback(elapsed);
|
||||
handleNoteDisplay();
|
||||
|
||||
// These ones only happen if the modal dialog is not open.
|
||||
|
@ -2471,7 +2509,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
// dispatchEvent gets called here.
|
||||
if (!super.beatHit()) return false;
|
||||
|
||||
if (isMetronomeEnabled && this.subState == null && (audioInstTrack != null && audioInstTrack.playing))
|
||||
if (isMetronomeEnabled && this.subState == null && (audioInstTrack != null && audioInstTrack.isPlaying))
|
||||
{
|
||||
playMetronomeTick(Conductor.currentBeat % 4 == 0);
|
||||
}
|
||||
|
@ -2487,7 +2525,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
// dispatchEvent gets called here.
|
||||
if (!super.stepHit()) return false;
|
||||
|
||||
if (audioInstTrack != null && audioInstTrack.playing)
|
||||
if (audioInstTrack != null && audioInstTrack.isPlaying)
|
||||
{
|
||||
if (healthIconDad != null) healthIconDad.onStepHit(Conductor.currentStep);
|
||||
if (healthIconBF != null) healthIconBF.onStepHit(Conductor.currentStep);
|
||||
|
@ -2508,18 +2546,26 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
/**
|
||||
* Handle syncronizing the conductor with the music playback.
|
||||
*/
|
||||
function handleMusicPlayback():Void
|
||||
function handleMusicPlayback(elapsed:Float):Void
|
||||
{
|
||||
if (audioInstTrack != null && audioInstTrack.playing)
|
||||
if (audioInstTrack != null)
|
||||
{
|
||||
// This normally gets called by FlxG.sound.update()
|
||||
// but we handle instrumental updates manually to prevent FlxG.sound.music.update()
|
||||
// from being called twice when we move to the PlayState.
|
||||
audioInstTrack.update(elapsed);
|
||||
}
|
||||
|
||||
if (audioInstTrack != null && audioInstTrack.isPlaying)
|
||||
{
|
||||
if (FlxG.mouse.pressedMiddle)
|
||||
{
|
||||
// If middle mouse panning during song playback, we move ONLY the playhead, without scrolling. Neat!
|
||||
|
||||
var oldStepTime:Float = Conductor.currentStepTime;
|
||||
var oldSongPosition:Float = Conductor.songPosition;
|
||||
var oldSongPosition:Float = Conductor.songPosition + Conductor.instrumentalOffset;
|
||||
Conductor.update(audioInstTrack.time);
|
||||
handleHitsounds(oldSongPosition, Conductor.songPosition);
|
||||
handleHitsounds(oldSongPosition, Conductor.songPosition + Conductor.instrumentalOffset);
|
||||
// Resync vocals.
|
||||
if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
|
||||
{
|
||||
|
@ -2535,9 +2581,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
else
|
||||
{
|
||||
// Else, move the entire view.
|
||||
var oldSongPosition:Float = Conductor.songPosition;
|
||||
var oldSongPosition:Float = Conductor.songPosition + Conductor.instrumentalOffset;
|
||||
Conductor.update(audioInstTrack.time);
|
||||
handleHitsounds(oldSongPosition, Conductor.songPosition);
|
||||
handleHitsounds(oldSongPosition, Conductor.songPosition + Conductor.instrumentalOffset);
|
||||
// Resync vocals.
|
||||
if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
|
||||
{
|
||||
|
@ -2546,7 +2592,7 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
|
||||
// We need time in fractional steps here to allow the song to actually play.
|
||||
// Also account for a potentially offset playhead.
|
||||
scrollPositionInPixels = Conductor.currentStepTime * GRID_SIZE - playheadPositionInPixels;
|
||||
scrollPositionInPixels = (Conductor.currentStepTime + Conductor.instrumentalOffsetSteps) * GRID_SIZE - playheadPositionInPixels;
|
||||
|
||||
// DO NOT move song to scroll position here specifically.
|
||||
|
||||
|
@ -3992,8 +4038,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
if (playbarHeadLayout.playbarHead.value != songPosPercent) playbarHeadLayout.playbarHead.value = songPosPercent;
|
||||
}
|
||||
|
||||
var songPosSeconds:String = Std.string(Math.floor((songPos / 1000) % 60)).lpad('0', 2);
|
||||
var songPosMinutes:String = Std.string(Math.floor((songPos / 1000) / 60)).lpad('0', 2);
|
||||
var songPosSeconds:String = Std.string(Math.floor((Math.abs(songPos) / 1000) % 60)).lpad('0', 2);
|
||||
var songPosMinutes:String = Std.string(Math.floor((Math.abs(songPos) / 1000) / 60)).lpad('0', 2);
|
||||
if (songPos < 0) songPosMinutes = '-' + songPosMinutes;
|
||||
var songPosString:String = '${songPosMinutes}:${songPosSeconds}';
|
||||
|
||||
if (playbarSongPos.value != songPosString) playbarSongPos.value = songPosString;
|
||||
|
@ -4313,6 +4360,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
{
|
||||
super.handleQuickWatch();
|
||||
|
||||
FlxG.watch.addQuick('musicTime', audioInstTrack?.time ?? 0.0);
|
||||
|
||||
FlxG.watch.addQuick('scrollPosInPixels', scrollPositionInPixels);
|
||||
FlxG.watch.addQuick('playheadPosInPixels', playheadPositionInPixels);
|
||||
|
||||
|
@ -4340,6 +4389,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
{
|
||||
autoSave();
|
||||
|
||||
stopWelcomeMusic();
|
||||
|
||||
var startTimestamp:Float = 0;
|
||||
if (playtestStartTime) startTimestamp = scrollPositionInMs + playheadPositionInMs;
|
||||
|
||||
|
@ -4394,7 +4445,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
});
|
||||
|
||||
// Override music.
|
||||
if (audioInstTrack != null) FlxG.sound.music = audioInstTrack;
|
||||
if (audioInstTrack != null)
|
||||
{
|
||||
FlxG.sound.music = audioInstTrack;
|
||||
}
|
||||
if (audioVocalTrackGroup != null) targetState.vocals = audioVocalTrackGroup;
|
||||
|
||||
this.persistentUpdate = false;
|
||||
|
@ -4523,6 +4577,23 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
this.switchToInstrumental(currentInstrumentalId, currentSongMetadata.playData.characters.player, currentSongMetadata.playData.characters.opponent);
|
||||
}
|
||||
|
||||
function onSongLengthChanged():Void
|
||||
{
|
||||
if (gridTiledSprite != null) gridTiledSprite.height = songLengthInPixels;
|
||||
if (gridPlayheadScrollArea != null)
|
||||
{
|
||||
gridPlayheadScrollArea.setGraphicSize(Std.int(gridPlayheadScrollArea.width), songLengthInPixels);
|
||||
gridPlayheadScrollArea.updateHitbox();
|
||||
}
|
||||
|
||||
scrollPositionInPixels = 0;
|
||||
playheadPositionInPixels = 0;
|
||||
notePreviewDirty = true;
|
||||
notePreviewViewportBoundsDirty = true;
|
||||
noteDisplayDirty = true;
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
* CHART DATA FUNCTIONS
|
||||
*/
|
||||
|
@ -4674,11 +4745,11 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
// Update the songPosition in the audio tracks.
|
||||
if (audioInstTrack != null)
|
||||
{
|
||||
audioInstTrack.time = scrollPositionInMs + playheadPositionInMs;
|
||||
audioInstTrack.time = scrollPositionInMs + playheadPositionInMs - Conductor.instrumentalOffset;
|
||||
// Update the songPosition in the Conductor.
|
||||
Conductor.update(audioInstTrack.time);
|
||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.time = audioInstTrack.time;
|
||||
}
|
||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.time = scrollPositionInMs + playheadPositionInMs;
|
||||
|
||||
// We need to update the note sprites because we changed the scroll position.
|
||||
noteDisplayDirty = true;
|
||||
|
@ -4738,6 +4809,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
|
||||
moveSongToScrollPosition();
|
||||
|
||||
fadeInWelcomeMusic(7, 10);
|
||||
|
||||
// Reapply the volume.
|
||||
var instTargetVolume:Float = menubarItemVolumeInstrumental.value ?? 1.0;
|
||||
var vocalTargetVolume:Float = menubarItemVolumeVocals.value ?? 1.0;
|
||||
|
@ -5034,15 +5107,17 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
{
|
||||
if (audioInstTrack == null) return;
|
||||
|
||||
if (audioInstTrack.playing)
|
||||
if (audioInstTrack.isPlaying)
|
||||
{
|
||||
fadeInWelcomeMusic(7, 10);
|
||||
// Pause
|
||||
stopAudioPlayback();
|
||||
fadeInWelcomeMusic(7, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
stopWelcomeMusic();
|
||||
// Play
|
||||
startAudioPlayback();
|
||||
stopWelcomeMusic();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5055,29 +5130,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
|||
if (audioInstTrack != null) audioInstTrack.pause();
|
||||
if (audioVocalTrackGroup != null) audioVocalTrackGroup.pause();
|
||||
};
|
||||
|
||||
songLengthInMs = audioInstTrack.length;
|
||||
|
||||
if (gridTiledSprite != null) gridTiledSprite.height = songLengthInPixels;
|
||||
if (gridPlayheadScrollArea != null)
|
||||
{
|
||||
gridPlayheadScrollArea.setGraphicSize(Std.int(gridPlayheadScrollArea.width), songLengthInPixels);
|
||||
gridPlayheadScrollArea.updateHitbox();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[WARN] Instrumental track was null!');
|
||||
trace('ERROR: Instrumental track is null!');
|
||||
}
|
||||
|
||||
// Pretty much everything is going to need to be reset.
|
||||
scrollPositionInPixels = 0;
|
||||
playheadPositionInPixels = 0;
|
||||
notePreviewDirty = true;
|
||||
notePreviewViewportBoundsDirty = true;
|
||||
noteDisplayDirty = true;
|
||||
state.songLengthInMs = state.audioInstTrack?.length ?? 1000.0 + Conductor.instrumentalOffset;
|
||||
|
||||
// Many things get reset when song length changes.
|
||||
healthIconsDirty = true;
|
||||
moveSongToScrollPosition();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -140,12 +140,14 @@ class ChartEditorAudioHandler
|
|||
{
|
||||
if (instId == '') instId = 'default';
|
||||
var instTrackData:Null<Bytes> = state.audioInstTrackData.get(instId);
|
||||
var instTrack:Null<FlxSound> = SoundUtil.buildFlxSoundFromBytes(instTrackData);
|
||||
var instTrack:Null<FunkinSound> = SoundUtil.buildSoundFromBytes(instTrackData);
|
||||
if (instTrack == null) return false;
|
||||
|
||||
stopExistingInstrumental(state);
|
||||
state.audioInstTrack = instTrack;
|
||||
state.postLoadInstrumental();
|
||||
// Workaround for a bug where FlxG.sound.music.update() was being called twice.
|
||||
FlxG.sound.list.remove(instTrack);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -176,17 +178,21 @@ class ChartEditorAudioHandler
|
|||
{
|
||||
case BF:
|
||||
state.audioVocalTrackGroup.addPlayerVoice(vocalTrack);
|
||||
state.audioVocalTrackGroup.playerVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||
return true;
|
||||
case DAD:
|
||||
state.audioVocalTrackGroup.addOpponentVoice(vocalTrack);
|
||||
state.audioVocalTrackGroup.opponentVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||
return true;
|
||||
case OTHER:
|
||||
state.audioVocalTrackGroup.add(vocalTrack);
|
||||
// TODO: Add offset for other characters.
|
||||
return true;
|
||||
default:
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -673,6 +673,7 @@ class ChartEditorDialogHandler
|
|||
|
||||
state.songMetadata.set(targetVariation, newSongMetadata);
|
||||
|
||||
Conductor.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata.
|
||||
Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges);
|
||||
|
||||
state.difficultySelectDirty = true;
|
||||
|
|
|
@ -115,6 +115,7 @@ class ChartEditorImportExportHandler
|
|||
state.songChartData = newSongChartData;
|
||||
|
||||
Conductor.forceBPM(null); // Disable the forced BPM.
|
||||
Conductor.instrumentalOffset = state.currentInstrumentalOffset; // Loads from the metadata.
|
||||
Conductor.mapTimeChanges(state.currentSongMetadata.timeChanges);
|
||||
|
||||
state.notePreviewDirty = true;
|
||||
|
|
|
@ -620,6 +620,27 @@ class ChartEditorToolboxHandler
|
|||
};
|
||||
inputBPM.value = state.currentSongMetadata.timeChanges[0].bpm;
|
||||
|
||||
var inputOffsetInst:Null<NumberStepper> = toolbox.findComponent('inputOffsetInst', NumberStepper);
|
||||
if (inputOffsetInst == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputOffsetInst component.';
|
||||
inputOffsetInst.onChange = function(event:UIEvent) {
|
||||
if (event.value == null) return;
|
||||
|
||||
state.currentInstrumentalOffset = event.value;
|
||||
Conductor.instrumentalOffset = event.value;
|
||||
// Update song length.
|
||||
state.songLengthInMs = state.audioInstTrack?.length ?? 1000.0 + Conductor.instrumentalOffset;
|
||||
};
|
||||
inputOffsetInst.value = state.currentInstrumentalOffset;
|
||||
|
||||
var inputOffsetVocal:Null<NumberStepper> = toolbox.findComponent('inputOffsetVocal', NumberStepper);
|
||||
if (inputOffsetVocal == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find inputOffsetVocal component.';
|
||||
inputOffsetVocal.onChange = function(event:UIEvent) {
|
||||
if (event.value == null) return;
|
||||
|
||||
state.currentSongMetadata.offsets.setVocalOffset(state.currentSongMetadata.playData.characters.player, event.value);
|
||||
};
|
||||
inputOffsetVocal.value = state.currentSongMetadata.offsets.getVocalOffset(state.currentSongMetadata.playData.characters.player);
|
||||
|
||||
var labelScrollSpeed:Null<Label> = toolbox.findComponent('labelScrollSpeed', Label);
|
||||
if (labelScrollSpeed == null) throw 'ChartEditorToolboxHandler.buildToolboxMetadataLayout() - Could not find labelScrollSpeed component.';
|
||||
|
||||
|
|
Loading…
Reference in a new issue