mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-01-01 09:48:14 +00:00
Chart wizard plus shader fixes
This commit is contained in:
parent
fbf92acf23
commit
19b2f3799a
4
hmm.json
4
hmm.json
|
@ -11,14 +11,14 @@
|
|||
"name": "flixel",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "6728df7",
|
||||
"ref": "8ff2aa9",
|
||||
"url": "https://github.com/MasterEric/flixel"
|
||||
},
|
||||
{
|
||||
"name": "flixel-addons",
|
||||
"type": "git",
|
||||
"dir": null,
|
||||
"ref": "a3877f0",
|
||||
"ref": "157eaf3",
|
||||
"url": "https://github.com/MasterEric/flixel-addons"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -129,6 +129,7 @@ class Conductor
|
|||
*/
|
||||
public static function forceBPM(bpm:Float)
|
||||
{
|
||||
trace('[CONDUCTOR] Forcing BPM to ' + bpm);
|
||||
Conductor.bpmOverride = bpm;
|
||||
}
|
||||
|
||||
|
@ -213,10 +214,8 @@ class Conductor
|
|||
}
|
||||
}
|
||||
|
||||
public static function mapTimeChanges(currentChart:SongDifficulty)
|
||||
public static function mapTimeChanges(songTimeChanges:Array<SongTimeChange>)
|
||||
{
|
||||
var songTimeChanges:Array<SongTimeChange> = currentChart.timeChanges;
|
||||
|
||||
timeChanges = [];
|
||||
|
||||
for (currentTimeChange in songTimeChanges)
|
||||
|
|
|
@ -7,30 +7,38 @@ import flixel.system.FlxSound;
|
|||
// when needed
|
||||
class VoicesGroup extends FlxTypedGroup<FlxSound>
|
||||
{
|
||||
public var time(default, set):Float = 0;
|
||||
public var time(get, set):Float;
|
||||
|
||||
public var volume(default, set):Float = 1;
|
||||
public var volume(get, set):Float;
|
||||
|
||||
public var pitch(default, set):Float = 1;
|
||||
public var pitch(get, set):Float;
|
||||
|
||||
// make it a group that you add to?
|
||||
public function new(song:String, ?files:Array<String> = null)
|
||||
public function new()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
// TODO: Remove this.
|
||||
public static function build(song:String, ?files:Array<String> = null):VoicesGroup
|
||||
{
|
||||
var result = new VoicesGroup();
|
||||
|
||||
if (files == null)
|
||||
{
|
||||
// Add an empty voice.
|
||||
add(new FlxSound());
|
||||
return;
|
||||
result.add(new FlxSound());
|
||||
return result;
|
||||
}
|
||||
|
||||
for (sndFile in files)
|
||||
{
|
||||
var snd:FlxSound = new FlxSound().loadEmbedded(Paths.voices(song, '$sndFile'));
|
||||
FlxG.sound.list.add(snd); // adds it to sound group for proper volumes
|
||||
add(snd); // adds it to main group for other shit
|
||||
result.add(snd); // adds it to main group for other shit
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -83,6 +91,14 @@ class VoicesGroup extends FlxTypedGroup<FlxSound>
|
|||
});
|
||||
}
|
||||
|
||||
function get_time():Float
|
||||
{
|
||||
if (getFirstAlive() != null)
|
||||
return getFirstAlive().time;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
function set_time(time:Float):Float
|
||||
{
|
||||
forEachAlive(function(snd)
|
||||
|
@ -94,6 +110,14 @@ class VoicesGroup extends FlxTypedGroup<FlxSound>
|
|||
return time;
|
||||
}
|
||||
|
||||
function get_volume():Float
|
||||
{
|
||||
if (getFirstAlive() != null)
|
||||
return getFirstAlive().volume;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
// in PlayState, adjust the code so that it only mutes the player1 vocal tracks?
|
||||
function set_volume(volume:Float):Float
|
||||
{
|
||||
|
@ -105,9 +129,20 @@ class VoicesGroup extends FlxTypedGroup<FlxSound>
|
|||
return volume;
|
||||
}
|
||||
|
||||
function get_pitch():Float
|
||||
{
|
||||
#if FLX_PITCH
|
||||
if (getFirstAlive() != null)
|
||||
return getFirstAlive().pitch;
|
||||
else
|
||||
#end
|
||||
return 1;
|
||||
}
|
||||
|
||||
function set_pitch(val:Float):Float
|
||||
{
|
||||
#if HAS_PITCH
|
||||
#if FLX_PITCH
|
||||
trace('Setting audio pitch to ' + val);
|
||||
forEachAlive(function(snd)
|
||||
{
|
||||
snd.pitch = val;
|
||||
|
|
|
@ -445,7 +445,7 @@ class ChartingState extends MusicBeatState
|
|||
add(playheadTest);
|
||||
|
||||
// WONT WORK FOR TUTORIAL OR TEST SONG!!! REDO LATER
|
||||
vocals = new VoicesGroup(daSong, _song.voiceList);
|
||||
vocals = VoicesGroup.build(daSong, _song.voiceList);
|
||||
// vocals = new FlxSound().loadEmbedded(Paths.voices(daSong));
|
||||
// FlxG.sound.list.add(vocals);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ class Cursor
|
|||
static final CURSOR_GRABBING_PARAMS:CursorParams = {
|
||||
graphic: "assets/images/cursor/cursor-grabbing.png",
|
||||
scale: 1.0,
|
||||
offsetX: 8,
|
||||
offsetX: 32,
|
||||
offsetY: 0,
|
||||
};
|
||||
static var assetCursorGrabbing:BitmapData = null;
|
||||
|
|
|
@ -354,7 +354,7 @@ class PlayState extends MusicBeatState
|
|||
|
||||
if (currentSong_NEW != null)
|
||||
{
|
||||
Conductor.mapTimeChanges(currentChart);
|
||||
Conductor.mapTimeChanges(currentChart.timeChanges);
|
||||
// Conductor.bpm = currentChart.getStartingBPM();
|
||||
|
||||
// TODO: Support for dialog.
|
||||
|
@ -1029,9 +1029,9 @@ class PlayState extends MusicBeatState
|
|||
currentSong.song = currentSong.song;
|
||||
|
||||
if (currentSong.needsVoices)
|
||||
vocals = new VoicesGroup(currentSong.song, currentSong.voiceList);
|
||||
vocals = VoicesGroup.build(currentSong.song, currentSong.voiceList);
|
||||
else
|
||||
vocals = new VoicesGroup(currentSong.song, null);
|
||||
vocals = VoicesGroup.build(currentSong.song, null);
|
||||
|
||||
vocals.members[0].onComplete = function()
|
||||
{
|
||||
|
|
|
@ -45,6 +45,11 @@ class Song // implements IPlayStateScriptedClass
|
|||
populateFromMetadata();
|
||||
}
|
||||
|
||||
public function getRawMetadata():Array<SongMetadata>
|
||||
{
|
||||
return _metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the song data from the provided metadata,
|
||||
* including data from individual difficulties. Does not load chart data.
|
||||
|
@ -246,7 +251,7 @@ class SongDifficulty
|
|||
|
||||
public function buildVocals(charId:String = "bf"):VoicesGroup
|
||||
{
|
||||
var result:VoicesGroup = new VoicesGroup(this.song.songId, this.buildVoiceList());
|
||||
var result:VoicesGroup = VoicesGroup.build(this.song.songId, this.buildVoiceList());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,12 +96,12 @@ class SongDataParser
|
|||
if (songCache.exists(songId))
|
||||
{
|
||||
var song:Song = songCache.get(songId);
|
||||
trace('[STAGEDATA] Successfully fetch song: ${songId}');
|
||||
trace('[SONGDATA] Successfully fetch song: ${songId}');
|
||||
return song;
|
||||
}
|
||||
else
|
||||
{
|
||||
trace('[STAGEDATA] Failed to fetch song, not found in cache: ${songId}');
|
||||
trace('[SONGDATA] Failed to fetch song, not found in cache: ${songId}');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,6 +110,25 @@ class ChartEditorDialogHandler
|
|||
}
|
||||
|
||||
// TODO: Get the list of songs and insert them as links into the "Create From Song" section.
|
||||
var linkTemplateDadBattle:Link = dialog.findComponent('splashTemplateDadBattle', Link);
|
||||
linkTemplateDadBattle.onClick = (_event) ->
|
||||
{
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
|
||||
// Load song from template
|
||||
state.loadSongAsTemplate('dadbattle');
|
||||
}
|
||||
var linkTemplateBopeebo:Link = dialog.findComponent('splashTemplateBopeebo', Link);
|
||||
linkTemplateBopeebo.onClick = (_event) ->
|
||||
{
|
||||
dialog.hideDialog(DialogButton.CANCEL);
|
||||
|
||||
// Load song from template
|
||||
state.loadSongAsTemplate('bopeebo');
|
||||
}
|
||||
|
||||
var splashTemplateContainer:VBox = dialog.findComponent('splashTemplateContainer', VBox);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
@ -237,7 +256,7 @@ class ChartEditorDialogHandler
|
|||
var dialogBPM:NumberStepper = dialog.findComponent('dialogBPM', NumberStepper);
|
||||
dialogBPM.onChange = (event:UIEvent) ->
|
||||
{
|
||||
if (event.value == null)
|
||||
if (event.value == null || event.value <= 0)
|
||||
return;
|
||||
|
||||
var timeChanges = state.currentSongMetadata.timeChanges;
|
||||
|
@ -249,6 +268,9 @@ class ChartEditorDialogHandler
|
|||
{
|
||||
timeChanges[0].bpm = event.value;
|
||||
}
|
||||
|
||||
Conductor.forceBPM(event.value);
|
||||
|
||||
state.currentSongMetadata.timeChanges = timeChanges;
|
||||
};
|
||||
|
||||
|
@ -388,9 +410,9 @@ class ChartEditorDialogHandler
|
|||
{
|
||||
if (selectedFile != null)
|
||||
{
|
||||
trace('Selected file: ' + selectedFile);
|
||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n$selectedFile';
|
||||
// state.loadVocalsFromBytes(selectedFile.bytes);
|
||||
trace('Selected file: ' + selectedFile.name + "~" + selectedFile.fullPath);
|
||||
vocalsEntryLabel.text = 'Vocals for $charName (click to browse)\n${selectedFile.name}';
|
||||
state.loadVocalsFromBytes(selectedFile.bytes);
|
||||
removeDropHandler(onDropFile);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package funkin.ui.debug.charting;
|
||||
|
||||
import funkin.play.song.SongData.SongDataParser;
|
||||
import funkin.play.song.Song;
|
||||
import lime.media.AudioBuffer;
|
||||
import funkin.input.Cursor;
|
||||
import flixel.FlxSprite;
|
||||
|
@ -433,7 +435,7 @@ class ChartEditorState extends HaxeUIState
|
|||
* The audio track for the vocals.
|
||||
* TODO: Replace with a VocalSoundGroup.
|
||||
*/
|
||||
var audioVocalTrack:FlxSound;
|
||||
var audioVocalTrackGroup:VoicesGroup;
|
||||
|
||||
/**
|
||||
* CHART DATA
|
||||
|
@ -758,7 +760,9 @@ class ChartEditorState extends HaxeUIState
|
|||
// TODO: We should be loading the music later when the user requests it.
|
||||
// loadDefaultMusic();
|
||||
|
||||
ChartEditorDialogHandler.openWelcomeDialog(this, false);
|
||||
// TODO: Change to false.
|
||||
var canCloseInitialDialog = true;
|
||||
ChartEditorDialogHandler.openWelcomeDialog(this, canCloseInitialDialog);
|
||||
}
|
||||
|
||||
function buildDefaultSongData()
|
||||
|
@ -771,6 +775,8 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
// Initialize the song chart data.
|
||||
songChartData = new Map<String, SongChartData>();
|
||||
|
||||
audioVocalTrackGroup = new VoicesGroup();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -933,7 +939,7 @@ class ChartEditorState extends HaxeUIState
|
|||
playbarHeadDragging = true;
|
||||
|
||||
// If we were dragging the playhead while the song was playing, resume playing.
|
||||
if (audioVocalTrack.playing)
|
||||
if (audioInstTrack != null && audioInstTrack.playing)
|
||||
{
|
||||
playbarHeadDraggingWasPlaying = true;
|
||||
stopAudioPlayback();
|
||||
|
@ -1057,16 +1063,35 @@ class ChartEditorState extends HaxeUIState
|
|||
});
|
||||
setUISelected('menubarItemMetronomeEnabled', shouldPlayMetronome);
|
||||
|
||||
var instVolumeLabel:Label = findComponent('menubarLabelVolumeInstrumental', Label);
|
||||
addUIChangeListener('menubarItemVolumeInstrumental', (event:UIEvent) ->
|
||||
{
|
||||
var volume:Float = event.value / 100.0;
|
||||
audioInstTrack.volume = volume;
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.volume = volume;
|
||||
instVolumeLabel.text = 'Instrumental - ${event.value}%';
|
||||
});
|
||||
|
||||
var vocalsVolumeLabel:Label = findComponent('menubarLabelVolumeVocals', Label);
|
||||
addUIChangeListener('menubarItemVolumeVocals', (event:UIEvent) ->
|
||||
{
|
||||
var volume:Float = event.value / 100.0;
|
||||
audioVocalTrack.volume = volume;
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.volume = volume;
|
||||
vocalsVolumeLabel.text = 'Vocals - ${event.value}%';
|
||||
});
|
||||
|
||||
var playbackSpeedLabel:Label = findComponent('menubarLabelPlaybackSpeed', Label);
|
||||
addUIChangeListener('menubarItemPlaybackSpeed', (event:UIEvent) ->
|
||||
{
|
||||
var pitch = event.value * 2.0 / 100.0;
|
||||
#if FLX_PITCH
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.pitch = pitch;
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.pitch = pitch;
|
||||
#end
|
||||
playbackSpeedLabel.text = 'Playback Speed - ${pitch}x';
|
||||
});
|
||||
|
||||
addUIChangeListener('menubarItemToggleToolboxTools', (event:UIEvent) ->
|
||||
|
@ -2242,8 +2267,8 @@ class ChartEditorState extends HaxeUIState
|
|||
var oldStepTime = Conductor.currentStepTime;
|
||||
Conductor.update(audioInstTrack.time);
|
||||
// Resync vocals.
|
||||
if (Math.abs(audioInstTrack.time - audioVocalTrack.time) > 100)
|
||||
audioVocalTrack.time = audioInstTrack.time;
|
||||
if (Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
|
||||
audioVocalTrackGroup.time = audioInstTrack.time;
|
||||
var diffStepTime = Conductor.currentStepTime - oldStepTime;
|
||||
|
||||
// Move the playhead.
|
||||
|
@ -2257,8 +2282,8 @@ class ChartEditorState extends HaxeUIState
|
|||
|
||||
Conductor.update(audioInstTrack.time);
|
||||
// Resync vocals.
|
||||
if (audioVocalTrack != null && Math.abs(audioInstTrack.time - audioVocalTrack.time) > 100)
|
||||
audioVocalTrack.time = audioInstTrack.time;
|
||||
if (audioVocalTrackGroup != null && Math.abs(audioInstTrack.time - audioVocalTrackGroup.time) > 100)
|
||||
audioVocalTrackGroup.time = audioInstTrack.time;
|
||||
|
||||
// We need time in fractional steps here to allow the song to actually play.
|
||||
// Also account for a potentially offset playhead.
|
||||
|
@ -2281,16 +2306,20 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.play();
|
||||
if (audioVocalTrack != null)
|
||||
audioVocalTrack.play();
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.play();
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.play();
|
||||
}
|
||||
|
||||
function stopAudioPlayback()
|
||||
{
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.pause();
|
||||
if (audioVocalTrack != null)
|
||||
audioVocalTrack.pause();
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.pause();
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.pause();
|
||||
}
|
||||
|
||||
function toggleAudioPlayback()
|
||||
|
@ -2418,8 +2447,12 @@ class ChartEditorState extends HaxeUIState
|
|||
*/
|
||||
public function loadInstrumentalFromPath(path:String):Void
|
||||
{
|
||||
#if sys
|
||||
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path);
|
||||
loadInstrumentalFromBytes(fileBytes);
|
||||
#else
|
||||
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
||||
#end
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2440,6 +2473,14 @@ class ChartEditorState extends HaxeUIState
|
|||
postLoadInstrumental();
|
||||
}
|
||||
|
||||
public function loadInstrumentalFromAsset(path:String):Void
|
||||
{
|
||||
var vocalTrack = FlxG.sound.load(path, 1.0, false);
|
||||
audioInstTrack = vocalTrack;
|
||||
|
||||
postLoadInstrumental();
|
||||
}
|
||||
|
||||
function postLoadInstrumental()
|
||||
{
|
||||
// Prevent the time from skipping back to 0 when the song ends.
|
||||
|
@ -2447,14 +2488,10 @@ class ChartEditorState extends HaxeUIState
|
|||
{
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.pause();
|
||||
if (audioVocalTrack != null)
|
||||
audioVocalTrack.pause();
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.pause();
|
||||
};
|
||||
|
||||
var DAD_BATTLE_BPM = 180;
|
||||
var BOPEEBO_BPM = 100;
|
||||
Conductor.forceBPM(DAD_BATTLE_BPM);
|
||||
|
||||
songLength = Std.int(Conductor.getTimeInSteps(audioInstTrack.length) * GRID_SIZE);
|
||||
|
||||
gridTiledSprite.height = songLength;
|
||||
|
@ -2470,20 +2507,79 @@ class ChartEditorState extends HaxeUIState
|
|||
}
|
||||
|
||||
/**
|
||||
* Load a music track for playback.
|
||||
* Loads a vocal track from an absolute file path.
|
||||
*/
|
||||
function loadDefaultMusic()
|
||||
public function loadVocalsFromPath(path:String):Void
|
||||
{
|
||||
// TODO: How to load music by selecting with a file dialog?
|
||||
audioInstTrack = FlxG.sound.play(Paths.inst('dadbattle'), 1.0, false);
|
||||
audioInstTrack.autoDestroy = false;
|
||||
audioInstTrack.pause();
|
||||
#if sys
|
||||
var fileBytes:haxe.io.Bytes = sys.io.File.getBytes(path);
|
||||
loadVocalsFromBytes(fileBytes);
|
||||
#else
|
||||
trace("[WARN] This platform can't load audio from a file path, you'll need to fetch the bytes some other way.");
|
||||
#end
|
||||
}
|
||||
|
||||
audioVocalTrack = FlxG.sound.play(Paths.voices('dadbattle'), 1.0, false);
|
||||
audioVocalTrack.autoDestroy = false;
|
||||
audioVocalTrack.pause();
|
||||
public function loadVocalsFromAsset(path:String):Void
|
||||
{
|
||||
var vocalTrack = FlxG.sound.load(path, 1.0, false);
|
||||
audioVocalTrackGroup.add(vocalTrack);
|
||||
}
|
||||
|
||||
postLoadInstrumental();
|
||||
/**
|
||||
* Loads a vocal track from audio byte data.
|
||||
*/
|
||||
public function loadVocalsFromBytes(bytes:haxe.io.Bytes):Void
|
||||
{
|
||||
var openflSound = new openfl.media.Sound();
|
||||
openflSound.loadCompressedDataFromByteArray(openfl.utils.ByteArray.fromBytes(bytes), bytes.length);
|
||||
var vocalTrack = FlxG.sound.load(openflSound, 1.0, false);
|
||||
audioVocalTrackGroup.add(vocalTrack);
|
||||
|
||||
// Tell the user the load was successful.
|
||||
// TODO: Un-bork this.
|
||||
// showNotification('Loaded instrumental track successfully.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch's a song's existing chart and audio and loads it, replacing the current song.
|
||||
*/
|
||||
public function loadSongAsTemplate(songId:String)
|
||||
{
|
||||
var song:Song = SongDataParser.fetchSong(songId);
|
||||
|
||||
if (song == null)
|
||||
{
|
||||
// showNotification('Failed to load song template.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the song metadata.
|
||||
var rawSongMetadata:Array<SongMetadata> = song.getRawMetadata();
|
||||
|
||||
this.songMetadata = new Map<String, SongMetadata>();
|
||||
|
||||
for (metadata in rawSongMetadata)
|
||||
{
|
||||
var variation = (metadata.variation == null || metadata.variation == '') ? 'default' : metadata.variation;
|
||||
this.songMetadata.set(variation, metadata);
|
||||
}
|
||||
|
||||
this.songChartData = new Map<String, SongChartData>();
|
||||
|
||||
for (metadata in rawSongMetadata)
|
||||
{
|
||||
var variation = (metadata.variation == null || metadata.variation == '') ? 'default' : metadata.variation;
|
||||
this.songChartData.set(variation, SongDataParser.parseSongChartData(songId, metadata.variation));
|
||||
}
|
||||
|
||||
Conductor.mapTimeChanges(currentSongMetadata.timeChanges);
|
||||
|
||||
loadInstrumentalFromAsset(Paths.inst(songId));
|
||||
loadVocalsFromAsset(Paths.voices(songId));
|
||||
|
||||
// Apply BPM
|
||||
|
||||
// showNotification('Loaded song ${songId}.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2498,8 +2594,8 @@ class ChartEditorState extends HaxeUIState
|
|||
// Update the songPosition in the audio tracks.
|
||||
if (audioInstTrack != null)
|
||||
audioInstTrack.time = scrollPositionInMs + playheadPositionInMs;
|
||||
if (audioVocalTrack != null)
|
||||
audioVocalTrack.time = scrollPositionInMs + playheadPositionInMs;
|
||||
if (audioVocalTrackGroup != null)
|
||||
audioVocalTrackGroup.time = scrollPositionInMs + playheadPositionInMs;
|
||||
|
||||
// We need to update the note sprites because we changed the scroll position.
|
||||
noteDisplayDirty = true;
|
||||
|
|
Loading…
Reference in a new issue