mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-03-23 02:19:46 +00:00
Merge pull request #99 from FunkinCrew/feature/split-vocals
Ported chart format (fixing story menu) and split vocals
This commit is contained in:
commit
6ab391d57a
2
hmm.json
2
hmm.json
|
@ -89,7 +89,7 @@
|
||||||
{
|
{
|
||||||
"name": "json2object",
|
"name": "json2object",
|
||||||
"type": "haxelib",
|
"type": "haxelib",
|
||||||
"version": null
|
"version": "3.11.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "lime",
|
"name": "lime",
|
||||||
|
|
|
@ -46,8 +46,7 @@ enum Control
|
||||||
#end
|
#end
|
||||||
}
|
}
|
||||||
|
|
||||||
@:enum
|
enum abstract Action(String) to String from String
|
||||||
abstract Action(String) to String from String
|
|
||||||
{
|
{
|
||||||
var UI_UP = "ui_up";
|
var UI_UP = "ui_up";
|
||||||
var UI_LEFT = "ui_left";
|
var UI_LEFT = "ui_left";
|
||||||
|
|
|
@ -882,10 +882,10 @@ class FreeplayState extends MusicBeatSubstate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override function switchTo(nextState:FlxState):Bool
|
override function startOutro(onComplete:() -> Void):Void
|
||||||
{
|
{
|
||||||
clearDaCache(songs[curSelected].songName);
|
clearDaCache(songs[curSelected].songName);
|
||||||
return super.switchTo(nextState);
|
super.startOutro(onComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDiff(change:Int = 0)
|
function changeDiff(change:Int = 0)
|
||||||
|
|
|
@ -144,7 +144,7 @@ class InputFormatter
|
||||||
}
|
}
|
||||||
|
|
||||||
@:forward
|
@:forward
|
||||||
@:enum abstract ControllerName(String) from String to String
|
enum abstract ControllerName(String) from String to String
|
||||||
{
|
{
|
||||||
var OUYA = "Ouya";
|
var OUYA = "Ouya";
|
||||||
var PS4 = "PS4";
|
var PS4 = "PS4";
|
||||||
|
|
|
@ -5,7 +5,7 @@ import flixel.FlxSubState;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.group.FlxGroup;
|
import flixel.group.FlxGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.system.debug.stats.StatsGraph;
|
import flixel.system.debug.stats.StatsGraph;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
|
|
|
@ -146,15 +146,20 @@ class MusicBeatState extends FlxUIState
|
||||||
sort(SortUtil.byZIndex, FlxSort.ASCENDING);
|
sort(SortUtil.byZIndex, FlxSort.ASCENDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function switchTo(nextState:FlxState):Bool
|
override function startOutro(onComplete:() -> Void):Void
|
||||||
{
|
{
|
||||||
var event = new StateChangeScriptEvent(ScriptEvent.STATE_CHANGE_BEGIN, nextState, true);
|
var event = new StateChangeScriptEvent(ScriptEvent.STATE_CHANGE_BEGIN, null, true);
|
||||||
|
|
||||||
dispatchEvent(event);
|
dispatchEvent(event);
|
||||||
|
|
||||||
if (event.eventCanceled) return false;
|
if (event.eventCanceled)
|
||||||
|
{
|
||||||
return super.switchTo(nextState);
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
onComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override function openSubState(targetSubstate:FlxSubState):Void
|
public override function openSubState(targetSubstate:FlxSubState):Void
|
||||||
|
|
|
@ -3,7 +3,7 @@ package funkin;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.tweens.FlxEase;
|
import flixel.tweens.FlxEase;
|
||||||
import flixel.tweens.FlxTween;
|
import flixel.tweens.FlxTween;
|
||||||
|
|
|
@ -119,16 +119,21 @@ class SongLoad
|
||||||
switch (diff)
|
switch (diff)
|
||||||
{
|
{
|
||||||
case 'easy':
|
case 'easy':
|
||||||
speedShit = songData.speed.easy;
|
speedShit = songData?.speed?.easy ?? 1.0;
|
||||||
case 'normal':
|
case 'normal':
|
||||||
speedShit = songData.speed.normal;
|
speedShit = songData?.speed?.normal ?? 1.0;
|
||||||
case 'hard':
|
case 'hard':
|
||||||
speedShit = songData.speed.hard;
|
speedShit = songData?.speed?.hard ?? 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (songData.speedMap[diff] == null) songData.speedMap[diff] = 1;
|
if (songData?.speedMap == null || songData?.speedMap[diff] == null)
|
||||||
|
{
|
||||||
|
speedShit = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
speedShit = songData.speedMap[diff];
|
speedShit = songData.speedMap[diff];
|
||||||
|
}
|
||||||
|
|
||||||
return speedShit;
|
return speedShit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin;
|
package funkin;
|
||||||
|
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
|
|
||||||
class TankCutscene extends FlxSprite
|
class TankCutscene extends FlxSprite
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,148 +0,0 @@
|
||||||
package funkin;
|
|
||||||
|
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
|
||||||
import flixel.system.FlxSound;
|
|
||||||
|
|
||||||
// different than FlxSoundGroup cuz this can control all the sounds time and shit
|
|
||||||
// when needed
|
|
||||||
class VoicesGroup extends FlxTypedGroup<FlxSound>
|
|
||||||
{
|
|
||||||
public var time(get, set):Float;
|
|
||||||
|
|
||||||
public var volume(get, set):Float;
|
|
||||||
|
|
||||||
public var pitch(get, set):Float;
|
|
||||||
|
|
||||||
// make it a group that you add to?
|
|
||||||
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.
|
|
||||||
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
|
|
||||||
result.add(snd); // adds it to main group for other shit
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds the largest deviation from the desired time inside this VoicesGroup.
|
|
||||||
*
|
|
||||||
* @param targetTime The time to check against.
|
|
||||||
* If none is provided, it checks the time of all members against the first member of this VoicesGroup.
|
|
||||||
* @return The largest deviation from the target time found.
|
|
||||||
*/
|
|
||||||
public function checkSyncError(?targetTime:Float):Float
|
|
||||||
{
|
|
||||||
var error:Float = 0;
|
|
||||||
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
if (targetTime == null) targetTime = snd.time;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var diff:Float = snd.time - targetTime;
|
|
||||||
if (Math.abs(diff) > Math.abs(error)) error = diff;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prob a better / cleaner way to do all these forEach stuff?
|
|
||||||
public function pause()
|
|
||||||
{
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
snd.pause();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function play()
|
|
||||||
{
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
snd.play();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function stop()
|
|
||||||
{
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
snd.stop();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function get_time():Float
|
|
||||||
{
|
|
||||||
if (getFirstAlive() != null) return getFirstAlive().time;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_time(time:Float):Float
|
|
||||||
{
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
// account for different offsets per sound?
|
|
||||||
snd.time = time;
|
|
||||||
});
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
snd.volume = volume;
|
|
||||||
});
|
|
||||||
|
|
||||||
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 FLX_PITCH
|
|
||||||
trace('Setting audio pitch to ' + val);
|
|
||||||
forEachAlive(function(snd)
|
|
||||||
{
|
|
||||||
snd.pitch = val;
|
|
||||||
});
|
|
||||||
#end
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,102 +1,67 @@
|
||||||
package funkin.audio;
|
package funkin.audio;
|
||||||
|
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A group of FlxSounds which can be controlled as a whole.
|
* A group of FlxSounds that are all synced together.
|
||||||
*
|
* Unlike FlxSoundGroup, you cann also control their time and pitch.
|
||||||
* Add sounds to the group using `add()`, and then control them
|
|
||||||
* as a whole using the properties and methods of this class.
|
|
||||||
*
|
|
||||||
* It is assumed that all the sounds will play at the same time,
|
|
||||||
* and have the same duration.
|
|
||||||
*/
|
*/
|
||||||
class FlxAudioGroup extends FlxTypedGroup<FlxSound>
|
class SoundGroup extends FlxTypedGroup<FlxSound>
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* The position in time of the sounds in the group.
|
|
||||||
* Measured in milliseconds.
|
|
||||||
*/
|
|
||||||
public var time(get, set):Float;
|
public var time(get, set):Float;
|
||||||
|
|
||||||
function get_time():Float
|
|
||||||
{
|
|
||||||
if (getFirstAlive() != null) return getFirstAlive().time;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_time(time:Float):Float
|
|
||||||
{
|
|
||||||
forEachAlive(function(sound:FlxSound) {
|
|
||||||
// account for different offsets per sound?
|
|
||||||
sound.time = time;
|
|
||||||
});
|
|
||||||
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The volume of the sounds in the group.
|
|
||||||
*/
|
|
||||||
public var volume(get, set):Float;
|
public var volume(get, set):Float;
|
||||||
|
|
||||||
function get_volume():Float
|
|
||||||
{
|
|
||||||
if (getFirstAlive() != null) return getFirstAlive().volume;
|
|
||||||
else
|
|
||||||
return 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function set_volume(volume:Float):Float
|
|
||||||
{
|
|
||||||
forEachAlive(function(sound:FlxSound) {
|
|
||||||
sound.volume = volume;
|
|
||||||
});
|
|
||||||
|
|
||||||
return volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The pitch of the sounds in the group, as a multiplier of 1.0x.
|
|
||||||
* `2.0` would play the audio twice as fast with a higher pitch,
|
|
||||||
* and `0.5` would play the audio at half speed with a lower pitch.
|
|
||||||
*/
|
|
||||||
public var pitch(get, set):Float;
|
public var pitch(get, set):Float;
|
||||||
|
|
||||||
function get_pitch():Float
|
public function new()
|
||||||
{
|
{
|
||||||
#if FLX_PITCH
|
super();
|
||||||
if (getFirstAlive() != null) return getFirstAlive().pitch;
|
|
||||||
else
|
|
||||||
#end
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_pitch(val:Float):Float
|
@:deprecated("Create sound files and call add() instead")
|
||||||
|
public static function build(song:String, ?files:Array<String> = null):SoundGroup
|
||||||
{
|
{
|
||||||
#if FLX_PITCH
|
var result = new SoundGroup();
|
||||||
trace('Setting audio pitch to ' + val);
|
|
||||||
forEachAlive(function(sound:FlxSound) {
|
if (files == null)
|
||||||
sound.pitch = val;
|
{
|
||||||
});
|
// Add an empty voice.
|
||||||
#end
|
result.add(new FlxSound());
|
||||||
return val;
|
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
|
||||||
|
result.add(snd); // adds it to main group for other shit
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether members of the group should be destroyed when they finish playing.
|
* Finds the largest deviation from the desired time inside this SoundGroup.
|
||||||
|
*
|
||||||
|
* @param targetTime The time to check against.
|
||||||
|
* If none is provided, it checks the time of all members against the first member of this SoundGroup.
|
||||||
|
* @return The largest deviation from the target time found.
|
||||||
*/
|
*/
|
||||||
public var autoDestroyMembers(default, set):Bool = false;
|
public function checkSyncError(?targetTime:Float):Float
|
||||||
|
|
||||||
function set_autoDestroyMembers(value:Bool):Bool
|
|
||||||
{
|
{
|
||||||
autoDestroyMembers = value;
|
var error:Float = 0;
|
||||||
forEachAlive(function(sound:FlxSound) {
|
|
||||||
sound.autoDestroy = value;
|
forEachAlive(function(snd) {
|
||||||
|
if (targetTime == null) targetTime = snd.time;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var diff:Float = snd.time - targetTime;
|
||||||
|
if (Math.abs(diff) > Math.abs(error)) error = diff;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return value;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,20 +73,25 @@ class FlxAudioGroup extends FlxTypedGroup<FlxSound>
|
||||||
|
|
||||||
if (result == null) return null;
|
if (result == null) return null;
|
||||||
|
|
||||||
// Apply parameters to the new sound.
|
|
||||||
result.autoDestroy = this.autoDestroyMembers;
|
|
||||||
result.pitch = this.pitch;
|
|
||||||
result.volume = this.volume;
|
|
||||||
|
|
||||||
// We have to play, then pause the sound to set the time,
|
// We have to play, then pause the sound to set the time,
|
||||||
// else the sound will restart immediately when played.
|
// else the sound will restart immediately when played.
|
||||||
result.play(true, 0.0);
|
result.play(true, 0.0);
|
||||||
result.pause();
|
result.pause();
|
||||||
result.time = this.time;
|
result.time = this.time;
|
||||||
|
|
||||||
|
result.onComplete = function() {
|
||||||
|
this.onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply parameters to the new sound.
|
||||||
|
result.pitch = this.pitch;
|
||||||
|
result.volume = this.volume;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public dynamic function onComplete():Void {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pause all the sounds in the group.
|
* Pause all the sounds in the group.
|
||||||
*/
|
*/
|
||||||
|
@ -162,6 +132,9 @@ class FlxAudioGroup extends FlxTypedGroup<FlxSound>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all sounds from the group.
|
||||||
|
*/
|
||||||
public override function clear():Void
|
public override function clear():Void
|
||||||
{
|
{
|
||||||
this.stop();
|
this.stop();
|
||||||
|
@ -169,26 +142,57 @@ class FlxAudioGroup extends FlxTypedGroup<FlxSound>
|
||||||
super.clear();
|
super.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function get_time():Float
|
||||||
* Calculates the deviation of the sounds in the group from the target time.
|
|
||||||
*
|
|
||||||
* @param targetTime The time to compare the sounds to.
|
|
||||||
* If null, the current time of the first sound in the group is used.
|
|
||||||
* @return The largest deviation of the sounds in the group from the target time.
|
|
||||||
*/
|
|
||||||
public function calcDeviation(?targetTime:Float):Float
|
|
||||||
{
|
{
|
||||||
var deviation:Float = 0;
|
if (getFirstAlive() != null) return getFirstAlive().time;
|
||||||
|
|
||||||
forEachAlive(function(sound:FlxSound) {
|
|
||||||
if (targetTime == null) targetTime = sound.time;
|
|
||||||
else
|
else
|
||||||
{
|
return 0;
|
||||||
var diff:Float = sound.time - targetTime;
|
|
||||||
if (Math.abs(diff) > Math.abs(deviation)) deviation = diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function set_time(time:Float):Float
|
||||||
|
{
|
||||||
|
forEachAlive(function(snd) {
|
||||||
|
// account for different offsets per sound?
|
||||||
|
snd.time = time;
|
||||||
});
|
});
|
||||||
|
|
||||||
return deviation;
|
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
|
||||||
|
{
|
||||||
|
forEachAlive(function(snd) {
|
||||||
|
snd.volume = volume;
|
||||||
|
});
|
||||||
|
|
||||||
|
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 FLX_PITCH
|
||||||
|
trace('Setting audio pitch to ' + val);
|
||||||
|
forEachAlive(function(snd) {
|
||||||
|
snd.pitch = val;
|
||||||
|
});
|
||||||
|
#end
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,119 +0,0 @@
|
||||||
package funkin.audio;
|
|
||||||
|
|
||||||
import flixel.system.FlxSound;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An audio group that allows for specific control of vocal tracks.
|
|
||||||
*/
|
|
||||||
class VocalGroup extends FlxAudioGroup
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* The player's vocal track.
|
|
||||||
*/
|
|
||||||
var playerVocals:FlxSound;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The opponent's vocal track.
|
|
||||||
*/
|
|
||||||
var opponentVocals:FlxSound;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The volume of the player's vocal track.
|
|
||||||
* Nore that this value is multiplied by the overall volume of the group.
|
|
||||||
*/
|
|
||||||
public var playerVolume(default, set):Float;
|
|
||||||
|
|
||||||
function set_playerVolume(value:Float):Float
|
|
||||||
{
|
|
||||||
playerVolume = value;
|
|
||||||
if (playerVocals != null)
|
|
||||||
{
|
|
||||||
// Make sure volume is capped at 1.0.
|
|
||||||
playerVocals.volume = Math.min(playerVolume * this.volume, 1.0);
|
|
||||||
}
|
|
||||||
return playerVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The volume of the opponent's vocal track.
|
|
||||||
* Nore that this value is multiplied by the overall volume of the group.
|
|
||||||
*/
|
|
||||||
public var opponentVolume(default, set):Float;
|
|
||||||
|
|
||||||
function set_opponentVolume(value:Float):Float
|
|
||||||
{
|
|
||||||
opponentVolume = value;
|
|
||||||
if (opponentVocals != null)
|
|
||||||
{
|
|
||||||
// Make sure volume is capped at 1.0.
|
|
||||||
opponentVocals.volume = opponentVolume * this.volume;
|
|
||||||
}
|
|
||||||
return opponentVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the player's vocal track.
|
|
||||||
* Stops and removes the existing player track if one exists.
|
|
||||||
*/
|
|
||||||
public function setPlayerVocals(sound:FlxSound):FlxSound
|
|
||||||
{
|
|
||||||
if (playerVocals != null)
|
|
||||||
{
|
|
||||||
playerVocals.stop();
|
|
||||||
remove(playerVocals);
|
|
||||||
playerVocals = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
playerVocals = add(sound);
|
|
||||||
playerVocals.volume = this.playerVolume * this.volume;
|
|
||||||
|
|
||||||
return playerVocals;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets up the opponent's vocal track.
|
|
||||||
* Stops and removes the existing player track if one exists.
|
|
||||||
*/
|
|
||||||
public function setOpponentVocals(sound:FlxSound):FlxSound
|
|
||||||
{
|
|
||||||
if (opponentVocals != null)
|
|
||||||
{
|
|
||||||
opponentVocals.stop();
|
|
||||||
remove(opponentVocals);
|
|
||||||
opponentVocals = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
opponentVocals = add(sound);
|
|
||||||
opponentVocals.volume = this.opponentVolume * this.volume;
|
|
||||||
|
|
||||||
return opponentVocals;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In this extension of FlxAudioGroup, there is a separate overall volume
|
|
||||||
* which affects all the members of the group.
|
|
||||||
*/
|
|
||||||
var _volume = 1.0;
|
|
||||||
|
|
||||||
override function get_volume():Float
|
|
||||||
{
|
|
||||||
return _volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
override function set_volume(value:Float):Float
|
|
||||||
{
|
|
||||||
_volume = super.set_volume(value);
|
|
||||||
|
|
||||||
if (playerVocals != null)
|
|
||||||
{
|
|
||||||
playerVocals.volume = playerVolume * _volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opponentVocals != null)
|
|
||||||
{
|
|
||||||
opponentVocals.volume = opponentVolume * _volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _volume;
|
|
||||||
}
|
|
||||||
}
|
|
68
source/funkin/audio/VoicesGroup.hx
Normal file
68
source/funkin/audio/VoicesGroup.hx
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
package funkin.audio;
|
||||||
|
|
||||||
|
import flixel.sound.FlxSound;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
|
||||||
|
class VoicesGroup extends SoundGroup
|
||||||
|
{
|
||||||
|
var playerVoices:FlxTypedGroup<FlxSound>;
|
||||||
|
var opponentVoices:FlxTypedGroup<FlxSound>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control the volume of only the sounds in the player group.
|
||||||
|
*/
|
||||||
|
public var playerVolume(default, set):Float;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Control the volume of only the sounds in the opponent group.
|
||||||
|
*/
|
||||||
|
public var opponentVolume(default, set):Float;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
playerVoices = new FlxTypedGroup<FlxSound>();
|
||||||
|
opponentVoices = new FlxTypedGroup<FlxSound>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a voice to the player group.
|
||||||
|
*/
|
||||||
|
public function addPlayerVoice(sound:FlxSound):Void
|
||||||
|
{
|
||||||
|
super.add(sound);
|
||||||
|
playerVoices.add(sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_playerVolume(volume:Float):Float
|
||||||
|
{
|
||||||
|
playerVoices.forEachAlive(function(voice:FlxSound) {
|
||||||
|
voice.volume = volume;
|
||||||
|
});
|
||||||
|
return playerVolume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a voice to the opponent group.
|
||||||
|
*/
|
||||||
|
public function addOpponentVoice(sound:FlxSound):Void
|
||||||
|
{
|
||||||
|
super.add(sound);
|
||||||
|
opponentVoices.add(sound);
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_opponentVolume(volume:Float):Float
|
||||||
|
{
|
||||||
|
opponentVoices.forEachAlive(function(voice:FlxSound) {
|
||||||
|
voice.volume = volume;
|
||||||
|
});
|
||||||
|
return opponentVolume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function clear():Void
|
||||||
|
{
|
||||||
|
playerVoices.clear();
|
||||||
|
opponentVoices.clear();
|
||||||
|
super.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ package funkin.audio.visualize;
|
||||||
|
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.audiovis.VisShit;
|
import funkin.audiovis.VisShit;
|
||||||
import funkin.graphics.rendering.MeshRender;
|
import funkin.graphics.rendering.MeshRender;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import flixel.addons.plugin.taskManager.FlxTask;
|
||||||
import flixel.graphics.frames.FlxAtlasFrames;
|
import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import funkin.ui.PreferencesMenu.CheckboxThingie;
|
import funkin.ui.PreferencesMenu.CheckboxThingie;
|
||||||
|
|
||||||
using Lambda;
|
using Lambda;
|
||||||
|
@ -86,8 +86,7 @@ class ABotVis extends FlxTypedSpriteGroup<FlxSprite>
|
||||||
|
|
||||||
for (i in 0...group.members.length)
|
for (i in 0...group.members.length)
|
||||||
{
|
{
|
||||||
var getSliceShit = function(s:Int)
|
var getSliceShit = function(s:Int) {
|
||||||
{
|
|
||||||
var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, CoolUtil.coolBaseLog(10, freqShit[0].length));
|
var powShit = FlxMath.remapToRange(s, 0, group.members.length, 0, CoolUtil.coolBaseLog(10, freqShit[0].length));
|
||||||
return Math.round(Math.pow(10, powShit));
|
return Math.round(Math.pow(10, powShit));
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,7 @@ import flixel.group.FlxSpriteGroup.FlxTypedSpriteGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.math.FlxVector;
|
import flixel.math.FlxVector;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.audio.visualize.PolygonSpectogram.VISTYPE;
|
import funkin.audio.visualize.PolygonSpectogram.VISTYPE;
|
||||||
import funkin.audiovis.VisShit.CurAudioInfo;
|
import funkin.audiovis.VisShit.CurAudioInfo;
|
||||||
|
@ -75,8 +75,7 @@ class SpectogramSprite extends FlxTypedSpriteGroup<FlxSprite>
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
forEach(spr ->
|
forEach(spr -> {
|
||||||
{
|
|
||||||
spr.visible = spr.ID % wavOptimiz == 0;
|
spr.visible = spr.ID % wavOptimiz == 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package funkin.audiovis;
|
package funkin.audiovis;
|
||||||
|
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import funkin.audiovis.dsp.FFT;
|
import funkin.audiovis.dsp.FFT;
|
||||||
import haxe.Timer;
|
import haxe.Timer;
|
||||||
import lime.system.ThreadPool;
|
import lime.system.ThreadPool;
|
||||||
|
@ -41,8 +41,7 @@ class VisShit
|
||||||
|
|
||||||
// helpers, note that spectrum indexes suppose non-negative frequencies
|
// helpers, note that spectrum indexes suppose non-negative frequencies
|
||||||
final binSize = fs / fftN;
|
final binSize = fs / fftN;
|
||||||
final indexToFreq = function(k:Int)
|
final indexToFreq = function(k:Int) {
|
||||||
{
|
|
||||||
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, CoolUtil.coolBaseLog(10, halfN)); // 4.3 is almost the log of 20Khz or so. Close enuf lol
|
var powShit:Float = FlxMath.remapToRange(k, 0, halfN, 0, CoolUtil.coolBaseLog(10, halfN)); // 4.3 is almost the log of 20Khz or so. Close enuf lol
|
||||||
|
|
||||||
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
|
return 1.0 * (Math.pow(10, powShit)); // we need the `1.0` to avoid overflows
|
||||||
|
@ -51,8 +50,7 @@ class VisShit
|
||||||
// "melodic" band-pass filter
|
// "melodic" band-pass filter
|
||||||
final minFreq = 20.70;
|
final minFreq = 20.70;
|
||||||
final maxFreq = 4000.01;
|
final maxFreq = 4000.01;
|
||||||
final melodicBandPass = function(k:Int, s:Float)
|
final melodicBandPass = function(k:Int, s:Float) {
|
||||||
{
|
|
||||||
final freq = indexToFreq(k);
|
final freq = indexToFreq(k);
|
||||||
final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
|
final filter = freq > minFreq - binSize && freq < maxFreq + binSize ? 1 : 0;
|
||||||
return s;
|
return s;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package funkin.charting;
|
package funkin.charting;
|
||||||
|
|
||||||
import flixel.FlxSprite;
|
|
||||||
import flixel.addons.display.FlxGridOverlay;
|
import flixel.addons.display.FlxGridOverlay;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.addons.ui.FlxInputText;
|
import flixel.addons.ui.FlxInputText;
|
||||||
|
@ -10,22 +9,24 @@ import flixel.addons.ui.FlxUIDropDownMenu;
|
||||||
import flixel.addons.ui.FlxUIInputText;
|
import flixel.addons.ui.FlxUIInputText;
|
||||||
import flixel.addons.ui.FlxUINumericStepper;
|
import flixel.addons.ui.FlxUINumericStepper;
|
||||||
import flixel.addons.ui.FlxUITabMenu;
|
import flixel.addons.ui.FlxUITabMenu;
|
||||||
|
import flixel.FlxSprite;
|
||||||
import flixel.group.FlxGroup;
|
import flixel.group.FlxGroup;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.ui.FlxButton;
|
import flixel.ui.FlxButton;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import funkin.Conductor.BPMChangeEvent;
|
|
||||||
import funkin.Section.SwagSection;
|
|
||||||
import funkin.SongLoad.SwagSong;
|
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import funkin.audiovis.ABotVis;
|
import funkin.audiovis.ABotVis;
|
||||||
import funkin.audiovis.SpectogramSprite;
|
import funkin.audiovis.SpectogramSprite;
|
||||||
|
import funkin.Conductor.BPMChangeEvent;
|
||||||
import funkin.graphics.rendering.MeshRender;
|
import funkin.graphics.rendering.MeshRender;
|
||||||
import funkin.noteStuff.NoteBasic.NoteData;
|
import funkin.noteStuff.NoteBasic.NoteData;
|
||||||
import funkin.play.HealthIcon;
|
import funkin.play.HealthIcon;
|
||||||
import funkin.play.PlayState;
|
import funkin.play.PlayState;
|
||||||
|
import funkin.Section.SwagSection;
|
||||||
|
import funkin.SongLoad.SwagSong;
|
||||||
|
import funkin.audio.VoicesGroup;
|
||||||
import haxe.Json;
|
import haxe.Json;
|
||||||
import lime.media.AudioBuffer;
|
import lime.media.AudioBuffer;
|
||||||
import lime.utils.Assets;
|
import lime.utils.Assets;
|
||||||
|
@ -193,16 +194,14 @@ class ChartingState extends MusicBeatState
|
||||||
var check_voices = new FlxUICheckBox(10, 25, null, null, "Has voice track", 100);
|
var check_voices = new FlxUICheckBox(10, 25, null, null, "Has voice track", 100);
|
||||||
check_voices.checked = _song.needsVoices;
|
check_voices.checked = _song.needsVoices;
|
||||||
// _song.needsVoices = check_voices.checked;
|
// _song.needsVoices = check_voices.checked;
|
||||||
check_voices.callback = function()
|
check_voices.callback = function() {
|
||||||
{
|
|
||||||
_song.needsVoices = check_voices.checked;
|
_song.needsVoices = check_voices.checked;
|
||||||
trace('CHECKED!');
|
trace('CHECKED!');
|
||||||
};
|
};
|
||||||
|
|
||||||
var check_mute_inst = new FlxUICheckBox(10, 200, null, null, "Mute Instrumental (in editor)", 100);
|
var check_mute_inst = new FlxUICheckBox(10, 200, null, null, "Mute Instrumental (in editor)", 100);
|
||||||
check_mute_inst.checked = false;
|
check_mute_inst.checked = false;
|
||||||
check_mute_inst.callback = function()
|
check_mute_inst.callback = function() {
|
||||||
{
|
|
||||||
var vol:Float = 1;
|
var vol:Float = 1;
|
||||||
|
|
||||||
if (check_mute_inst.checked) vol = 0;
|
if (check_mute_inst.checked) vol = 0;
|
||||||
|
@ -210,23 +209,19 @@ class ChartingState extends MusicBeatState
|
||||||
FlxG.sound.music.volume = vol;
|
FlxG.sound.music.volume = vol;
|
||||||
};
|
};
|
||||||
|
|
||||||
var saveButton:FlxButton = new FlxButton(110, 8, "Save", function()
|
var saveButton:FlxButton = new FlxButton(110, 8, "Save", function() {
|
||||||
{
|
|
||||||
saveLevel();
|
saveLevel();
|
||||||
});
|
});
|
||||||
|
|
||||||
var saveCompiler:FlxButton = new FlxButton(110, 30, "Save compile", function()
|
var saveCompiler:FlxButton = new FlxButton(110, 30, "Save compile", function() {
|
||||||
{
|
|
||||||
saveLevel(true);
|
saveLevel(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
var reloadSong:FlxButton = new FlxButton(saveButton.x + saveButton.width + 10, saveButton.y, "Reload Audio", function()
|
var reloadSong:FlxButton = new FlxButton(saveButton.x + saveButton.width + 10, saveButton.y, "Reload Audio", function() {
|
||||||
{
|
|
||||||
loadSong(_song.song);
|
loadSong(_song.song);
|
||||||
});
|
});
|
||||||
|
|
||||||
var reloadSongJson:FlxButton = new FlxButton(reloadSong.x, saveButton.y + 30, "Reload JSON", function()
|
var reloadSongJson:FlxButton = new FlxButton(reloadSong.x, saveButton.y + 30, "Reload JSON", function() {
|
||||||
{
|
|
||||||
FlxTransitionableState.skipNextTransIn = true;
|
FlxTransitionableState.skipNextTransIn = true;
|
||||||
FlxTransitionableState.skipNextTransOut = true;
|
FlxTransitionableState.skipNextTransOut = true;
|
||||||
loadJson(_song.song.toLowerCase());
|
loadJson(_song.song.toLowerCase());
|
||||||
|
@ -245,22 +240,19 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
var characters:Array<String> = CoolUtil.coolTextFile(Paths.txt('characterList'));
|
var characters:Array<String> = CoolUtil.coolTextFile(Paths.txt('characterList'));
|
||||||
|
|
||||||
var player1DropDown = new FlxUIDropDownMenu(10, 100, FlxUIDropDownMenu.makeStrIdLabelArray(characters, true), function(character:String)
|
var player1DropDown = new FlxUIDropDownMenu(10, 100, FlxUIDropDownMenu.makeStrIdLabelArray(characters, true), function(character:String) {
|
||||||
{
|
|
||||||
_song.player1 = characters[Std.parseInt(character)];
|
_song.player1 = characters[Std.parseInt(character)];
|
||||||
updateHeads();
|
updateHeads();
|
||||||
});
|
});
|
||||||
player1DropDown.selectedLabel = _song.player1;
|
player1DropDown.selectedLabel = _song.player1;
|
||||||
|
|
||||||
var player2DropDown = new FlxUIDropDownMenu(140, 100, FlxUIDropDownMenu.makeStrIdLabelArray(characters, true), function(character:String)
|
var player2DropDown = new FlxUIDropDownMenu(140, 100, FlxUIDropDownMenu.makeStrIdLabelArray(characters, true), function(character:String) {
|
||||||
{
|
|
||||||
_song.player2 = characters[Std.parseInt(character)];
|
_song.player2 = characters[Std.parseInt(character)];
|
||||||
updateHeads();
|
updateHeads();
|
||||||
});
|
});
|
||||||
player2DropDown.selectedLabel = _song.player2;
|
player2DropDown.selectedLabel = _song.player2;
|
||||||
|
|
||||||
var difficultyDropDown = new FlxUIDropDownMenu(10, 230, FlxUIDropDownMenu.makeStrIdLabelArray(_song.difficulties, true), function(diff:String)
|
var difficultyDropDown = new FlxUIDropDownMenu(10, 230, FlxUIDropDownMenu.makeStrIdLabelArray(_song.difficulties, true), function(diff:String) {
|
||||||
{
|
|
||||||
SongLoad.curDiff = _song.difficulties[Std.parseInt(diff)];
|
SongLoad.curDiff = _song.difficulties[Std.parseInt(diff)];
|
||||||
SongLoad.checkAndCreateNotemap(SongLoad.curDiff);
|
SongLoad.checkAndCreateNotemap(SongLoad.curDiff);
|
||||||
|
|
||||||
|
@ -273,8 +265,7 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
var difficultyAdder = new FlxUIInputText(130, 230, 100, "", 12);
|
var difficultyAdder = new FlxUIInputText(130, 230, 100, "", 12);
|
||||||
|
|
||||||
var addDiff:FlxButton = new FlxButton(130, 250, "Add Difficulty", function()
|
var addDiff:FlxButton = new FlxButton(130, 250, "Add Difficulty", function() {
|
||||||
{
|
|
||||||
difficultyAdder.text = "";
|
difficultyAdder.text = "";
|
||||||
// something to regenerate difficulties
|
// something to regenerate difficulties
|
||||||
});
|
});
|
||||||
|
@ -325,15 +316,13 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
var stepperCopy:FlxUINumericStepper = new FlxUINumericStepper(110, 130, 1, 1, -999, 999, 0);
|
var stepperCopy:FlxUINumericStepper = new FlxUINumericStepper(110, 130, 1, 1, -999, 999, 0);
|
||||||
|
|
||||||
var copyButton:FlxButton = new FlxButton(10, 130, "Copy last section", function()
|
var copyButton:FlxButton = new FlxButton(10, 130, "Copy last section", function() {
|
||||||
{
|
|
||||||
copySection(Std.int(stepperCopy.value));
|
copySection(Std.int(stepperCopy.value));
|
||||||
});
|
});
|
||||||
|
|
||||||
var clearSectionButton:FlxButton = new FlxButton(10, 150, "Clear", clearSection);
|
var clearSectionButton:FlxButton = new FlxButton(10, 150, "Clear", clearSection);
|
||||||
|
|
||||||
var swapSection:FlxButton = new FlxButton(10, 170, "Swap section", function()
|
var swapSection:FlxButton = new FlxButton(10, 170, "Swap section", function() {
|
||||||
{
|
|
||||||
for (i in 0...SongLoad.getSong()[curSection].sectionNotes.length)
|
for (i in 0...SongLoad.getSong()[curSection].sectionNotes.length)
|
||||||
{
|
{
|
||||||
var note:Note = new Note(0, 0);
|
var note:Note = new Note(0, 0);
|
||||||
|
@ -417,8 +406,7 @@ class ChartingState extends MusicBeatState
|
||||||
// @:privateAccess
|
// @:privateAccess
|
||||||
// library.pathGroups.set(symbolPath, [library.__cacheBreak(symbolPath)]);
|
// library.pathGroups.set(symbolPath, [library.__cacheBreak(symbolPath)]);
|
||||||
// var callback = callbacks.add("song:" + pathShit);
|
// var callback = callbacks.add("song:" + pathShit);
|
||||||
openfl.utils.Assets.loadSound(pathShit).onComplete(function(_)
|
openfl.utils.Assets.loadSound(pathShit).onComplete(function(_) {
|
||||||
{
|
|
||||||
// callback();
|
// callback();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -443,7 +431,7 @@ class ChartingState extends MusicBeatState
|
||||||
add(playheadTest);
|
add(playheadTest);
|
||||||
|
|
||||||
// WONT WORK FOR TUTORIAL OR TEST SONG!!! REDO LATER
|
// WONT WORK FOR TUTORIAL OR TEST SONG!!! REDO LATER
|
||||||
vocals = VoicesGroup.build(daSong, _song.voiceList);
|
vocals = new VoicesGroup();
|
||||||
// vocals = new FlxSound().loadEmbedded(Paths.voices(daSong));
|
// vocals = new FlxSound().loadEmbedded(Paths.voices(daSong));
|
||||||
// FlxG.sound.list.add(vocals);
|
// FlxG.sound.list.add(vocals);
|
||||||
|
|
||||||
|
@ -477,8 +465,7 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
vocals.pause();
|
vocals.pause();
|
||||||
|
|
||||||
FlxG.sound.music.onComplete = function()
|
FlxG.sound.music.onComplete = function() {
|
||||||
{
|
|
||||||
vocals.pause();
|
vocals.pause();
|
||||||
vocals.time = 0;
|
vocals.time = 0;
|
||||||
FlxG.sound.music.pause();
|
FlxG.sound.music.pause();
|
||||||
|
@ -742,8 +729,7 @@ class ChartingState extends MusicBeatState
|
||||||
|
|
||||||
if (FlxG.mouse.overlaps(curRenderedNotes))
|
if (FlxG.mouse.overlaps(curRenderedNotes))
|
||||||
{
|
{
|
||||||
curRenderedNotes.forEach(function(note:Note)
|
curRenderedNotes.forEach(function(note:Note) {
|
||||||
{
|
|
||||||
if (FlxG.mouse.overlaps(note))
|
if (FlxG.mouse.overlaps(note))
|
||||||
{
|
{
|
||||||
selectNote(note);
|
selectNote(note);
|
||||||
|
@ -766,8 +752,7 @@ class ChartingState extends MusicBeatState
|
||||||
{
|
{
|
||||||
if (FlxG.mouse.overlaps(curRenderedNotes))
|
if (FlxG.mouse.overlaps(curRenderedNotes))
|
||||||
{
|
{
|
||||||
curRenderedNotes.forEach(function(note:Note)
|
curRenderedNotes.forEach(function(note:Note) {
|
||||||
{
|
|
||||||
if (FlxG.mouse.overlaps(note))
|
if (FlxG.mouse.overlaps(note))
|
||||||
{
|
{
|
||||||
trace('tryin to delete note...');
|
trace('tryin to delete note...');
|
||||||
|
@ -1151,8 +1136,7 @@ class ChartingState extends MusicBeatState
|
||||||
// null if checks jus cuz i put updateGrid() in some weird places!
|
// null if checks jus cuz i put updateGrid() in some weird places!
|
||||||
if (staticSpecGrp != null)
|
if (staticSpecGrp != null)
|
||||||
{
|
{
|
||||||
staticSpecGrp.forEach(function(spec)
|
staticSpecGrp.forEach(function(spec) {
|
||||||
{
|
|
||||||
if (spec != null) spec.generateSection(sectionStartTime(), (Conductor.stepCrochet * 32) / 1000);
|
if (spec != null) spec.generateSection(sectionStartTime(), (Conductor.stepCrochet * 32) / 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
package funkin.play;
|
package funkin.play;
|
||||||
|
|
||||||
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
|
import flixel.sound.FlxSound;
|
||||||
|
import flixel.addons.transition.FlxTransitionableState;
|
||||||
import flixel.FlxCamera;
|
import flixel.FlxCamera;
|
||||||
import flixel.FlxObject;
|
import flixel.FlxObject;
|
||||||
import funkin.ui.story.StoryMenuState;
|
import funkin.ui.story.StoryMenuState;
|
||||||
import flixel.FlxSprite;
|
import flixel.FlxSprite;
|
||||||
import flixel.FlxState;
|
import flixel.FlxState;
|
||||||
import flixel.FlxSubState;
|
import flixel.FlxSubState;
|
||||||
import flixel.addons.transition.FlxTransitionableState;
|
|
||||||
import flixel.group.FlxGroup.FlxTypedGroup;
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
import flixel.input.keyboard.FlxKey;
|
import flixel.input.keyboard.FlxKey;
|
||||||
import flixel.math.FlxMath;
|
import flixel.math.FlxMath;
|
||||||
|
@ -18,18 +20,14 @@ import flixel.ui.FlxBar;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSort;
|
import flixel.util.FlxSort;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.Highscore.Tallies;
|
|
||||||
import funkin.Note;
|
|
||||||
import funkin.Section.SwagSection;
|
|
||||||
import funkin.SongLoad.SwagSong;
|
|
||||||
import funkin.charting.ChartingState;
|
import funkin.charting.ChartingState;
|
||||||
|
import funkin.Highscore.Tallies;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.modding.events.ScriptEventDispatcher;
|
import funkin.modding.events.ScriptEventDispatcher;
|
||||||
import funkin.play.Strumline.StrumlineArrow;
|
import funkin.Note;
|
||||||
import funkin.play.Strumline.StrumlineStyle;
|
|
||||||
import funkin.play.character.BaseCharacter;
|
import funkin.play.character.BaseCharacter;
|
||||||
import funkin.play.character.CharacterData.CharacterDataParser;
|
|
||||||
import funkin.play.character.CharacterData;
|
import funkin.play.character.CharacterData;
|
||||||
|
import funkin.play.character.CharacterData.CharacterDataParser;
|
||||||
import funkin.play.cutscene.VanillaCutscenes;
|
import funkin.play.cutscene.VanillaCutscenes;
|
||||||
import funkin.play.event.SongEvent.SongEventParser;
|
import funkin.play.event.SongEvent.SongEventParser;
|
||||||
import funkin.play.scoring.Scoring;
|
import funkin.play.scoring.Scoring;
|
||||||
|
@ -40,6 +38,11 @@ import funkin.play.song.SongData.SongPlayableChar;
|
||||||
import funkin.play.song.SongValidator;
|
import funkin.play.song.SongValidator;
|
||||||
import funkin.play.stage.Stage;
|
import funkin.play.stage.Stage;
|
||||||
import funkin.play.stage.StageData.StageDataParser;
|
import funkin.play.stage.StageData.StageDataParser;
|
||||||
|
import funkin.play.Strumline.StrumlineArrow;
|
||||||
|
import funkin.play.Strumline.StrumlineStyle;
|
||||||
|
import funkin.Section.SwagSection;
|
||||||
|
import funkin.SongLoad.SwagSong;
|
||||||
|
import funkin.audio.VoicesGroup;
|
||||||
import funkin.ui.PopUpStuff;
|
import funkin.ui.PopUpStuff;
|
||||||
import funkin.ui.PreferencesMenu;
|
import funkin.ui.PreferencesMenu;
|
||||||
import funkin.ui.stageBuildShit.StageOffsetSubstate;
|
import funkin.ui.stageBuildShit.StageOffsetSubstate;
|
||||||
|
@ -360,7 +363,7 @@ class PlayState extends MusicBeatState
|
||||||
if (currentChart != null)
|
if (currentChart != null)
|
||||||
{
|
{
|
||||||
currentChart.cacheInst();
|
currentChart.cacheInst();
|
||||||
currentChart.cacheVocals();
|
currentChart.cacheVocals('bf');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1060,9 +1063,11 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
currentSong.song = currentSong.song;
|
currentSong.song = currentSong.song;
|
||||||
|
|
||||||
if (currentSong.needsVoices) vocals = VoicesGroup.build(currentSong.song, currentSong.voiceList);
|
vocals = new VoicesGroup();
|
||||||
else
|
var playerVocals:FlxSound = FlxG.sound.load(Paths.voices(currentSong.song, 'bf'), 1.0, false);
|
||||||
vocals = VoicesGroup.build(currentSong.song, null);
|
vocals.addPlayerVoice(playerVocals);
|
||||||
|
var opponentVocals:FlxSound = FlxG.sound.load(Paths.voices(currentSong.song, 'dad'), 1.0, false);
|
||||||
|
vocals.addOpponentVoice(opponentVocals);
|
||||||
|
|
||||||
vocals.members[0].onComplete = function() {
|
vocals.members[0].onComplete = function() {
|
||||||
vocalsFinished = true;
|
vocalsFinished = true;
|
||||||
|
@ -1088,7 +1093,7 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
// TODO: Fix grouped vocals
|
// TODO: Fix grouped vocals
|
||||||
vocals = currentChart.buildVocals();
|
vocals = currentChart.buildVocals();
|
||||||
vocals.members[0].onComplete = function() {
|
vocals.onComplete = function() {
|
||||||
vocalsFinished = true;
|
vocalsFinished = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1428,6 +1433,8 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
FlxG.sound.music.volume = 1;
|
FlxG.sound.music.volume = 1;
|
||||||
vocals.volume = 1;
|
vocals.volume = 1;
|
||||||
|
vocals.playerVolume = 1;
|
||||||
|
vocals.opponentVolume = 1;
|
||||||
|
|
||||||
currentStage.resetStage();
|
currentStage.resetStage();
|
||||||
|
|
||||||
|
@ -1720,7 +1727,7 @@ class PlayState extends MusicBeatState
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Volume of DAD.
|
// Volume of DAD.
|
||||||
if (currentSong != null && currentSong.needsVoices) vocals.volume = 1;
|
if (currentSong != null && currentSong.needsVoices) vocals.opponentVolume = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1904,7 +1911,7 @@ class PlayState extends MusicBeatState
|
||||||
// if ()
|
// if ()
|
||||||
StoryMenuState.weekUnlocked[Std.int(Math.min(storyWeek + 1, StoryMenuState.weekUnlocked.length - 1))] = true;
|
StoryMenuState.weekUnlocked[Std.int(Math.min(storyWeek + 1, StoryMenuState.weekUnlocked.length - 1))] = true;
|
||||||
|
|
||||||
if (currentSong.validScore)
|
if (currentSong?.validScore)
|
||||||
{
|
{
|
||||||
NGio.unlockMedal(60961);
|
NGio.unlockMedal(60961);
|
||||||
Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty);
|
Highscore.saveWeekScore(storyWeek, campaignScore, storyDifficulty);
|
||||||
|
@ -1930,7 +1937,7 @@ class PlayState extends MusicBeatState
|
||||||
FlxG.sound.music.stop();
|
FlxG.sound.music.stop();
|
||||||
vocals.stop();
|
vocals.stop();
|
||||||
|
|
||||||
if (currentSong.song.toLowerCase() == 'eggnog')
|
if ((currentSong?.song ?? '').toLowerCase() == 'eggnog')
|
||||||
{
|
{
|
||||||
var blackShit:FlxSprite = new FlxSprite(-FlxG.width * FlxG.camera.zoom,
|
var blackShit:FlxSprite = new FlxSprite(-FlxG.width * FlxG.camera.zoom,
|
||||||
-FlxG.height * FlxG.camera.zoom).makeGraphic(FlxG.width * 3, FlxG.height * 3, FlxColor.BLACK);
|
-FlxG.height * FlxG.camera.zoom).makeGraphic(FlxG.width * 3, FlxG.height * 3, FlxColor.BLACK);
|
||||||
|
@ -1949,7 +1956,7 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
previousCameraFollowPoint = cameraFollowPoint;
|
previousCameraFollowPoint = cameraFollowPoint;
|
||||||
|
|
||||||
currentSong = SongLoad.loadFromJson(storyPlaylist[0].toLowerCase() + difficulty, storyPlaylist[0]);
|
currentSong_NEW = SongDataParser.fetchSong(PlayState.storyPlaylist[0].toLowerCase());
|
||||||
LoadingState.loadAndSwitchState(new PlayState());
|
LoadingState.loadAndSwitchState(new PlayState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1993,7 +2000,7 @@ class PlayState extends MusicBeatState
|
||||||
{
|
{
|
||||||
var noteDiff:Float = Math.abs(strumtime - Conductor.songPosition);
|
var noteDiff:Float = Math.abs(strumtime - Conductor.songPosition);
|
||||||
// boyfriend.playAnimation('hey');
|
// boyfriend.playAnimation('hey');
|
||||||
vocals.volume = 1;
|
vocals.playerVolume = 1;
|
||||||
|
|
||||||
var isSick:Bool = false;
|
var isSick:Bool = false;
|
||||||
var score = Scoring.scoreNote(noteDiff, PBOT1);
|
var score = Scoring.scoreNote(noteDiff, PBOT1);
|
||||||
|
@ -2125,7 +2132,6 @@ class PlayState extends MusicBeatState
|
||||||
// TODO: Un-hardcode this stuff.
|
// TODO: Un-hardcode this stuff.
|
||||||
if (currentStage.getDad().characterId == 'mom')
|
if (currentStage.getDad().characterId == 'mom')
|
||||||
{
|
{
|
||||||
vocals.volume = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentSong.song.toLowerCase() == 'tutorial')
|
if (currentSong.song.toLowerCase() == 'tutorial')
|
||||||
|
@ -2313,7 +2319,7 @@ class PlayState extends MusicBeatState
|
||||||
|
|
||||||
if (event.playSound)
|
if (event.playSound)
|
||||||
{
|
{
|
||||||
vocals.volume = 0;
|
vocals.playerVolume = 0;
|
||||||
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
FlxG.sound.play(Paths.soundRandom('missnote', 1, 3), FlxG.random.float(0.1, 0.2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2368,7 +2374,7 @@ class PlayState extends MusicBeatState
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vocals.volume = 0;
|
vocals.playerVolume = 0;
|
||||||
|
|
||||||
if (Highscore.tallies.combo != 0)
|
if (Highscore.tallies.combo != 0)
|
||||||
{
|
{
|
||||||
|
@ -2406,7 +2412,7 @@ class PlayState extends MusicBeatState
|
||||||
playerStrumline.getArrow(note.data.noteData).playAnimation('confirm', true);
|
playerStrumline.getArrow(note.data.noteData).playAnimation('confirm', true);
|
||||||
|
|
||||||
note.wasGoodHit = true;
|
note.wasGoodHit = true;
|
||||||
vocals.volume = 1;
|
vocals.playerVolume = 1;
|
||||||
|
|
||||||
if (!note.isSustainNote)
|
if (!note.isSustainNote)
|
||||||
{
|
{
|
||||||
|
@ -2743,15 +2749,10 @@ class PlayState extends MusicBeatState
|
||||||
* This function is called whenever Flixel switches switching to a new FlxState.
|
* This function is called whenever Flixel switches switching to a new FlxState.
|
||||||
* @return Whether to actually switch to the new state.
|
* @return Whether to actually switch to the new state.
|
||||||
*/
|
*/
|
||||||
override function switchTo(nextState:FlxState):Bool
|
override function startOutro(onComplete:() -> Void):Void
|
||||||
{
|
|
||||||
var result = super.switchTo(nextState);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
{
|
||||||
performCleanup();
|
performCleanup();
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
onComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ typedef AnimateAtlasAnimation =
|
||||||
{
|
{
|
||||||
name:String,
|
name:String,
|
||||||
prefix:String,
|
prefix:String,
|
||||||
offset:Null<Array<Float>>,
|
offsets:Null<Array<Float>>,
|
||||||
loop:Bool,
|
looped:Bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -107,7 +107,7 @@ class AnimateAtlasCharacter extends BaseCharacter
|
||||||
{
|
{
|
||||||
super.onAnimationFinished(prefix);
|
super.onAnimationFinished(prefix);
|
||||||
|
|
||||||
if (getAnimationData() != null && getAnimationData().loop)
|
if (getAnimationData() != null && getAnimationData().looped)
|
||||||
{
|
{
|
||||||
playAnimation(prefix, true, false);
|
playAnimation(prefix, true, false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package funkin.play.song;
|
package funkin.play.song;
|
||||||
|
|
||||||
import funkin.VoicesGroup;
|
import flixel.sound.FlxSound;
|
||||||
import funkin.play.event.SongEvent;
|
import openfl.utils.Assets;
|
||||||
|
import funkin.modding.events.ScriptEvent;
|
||||||
|
import funkin.modding.IScriptedClass;
|
||||||
|
import funkin.audio.VoicesGroup;
|
||||||
import funkin.play.song.SongData.SongChartData;
|
import funkin.play.song.SongData.SongChartData;
|
||||||
import funkin.play.song.SongData.SongDataParser;
|
import funkin.play.song.SongData.SongDataParser;
|
||||||
import funkin.play.song.SongData.SongEventData;
|
import funkin.play.song.SongData.SongEventData;
|
||||||
|
@ -20,7 +23,7 @@ import funkin.play.song.SongData.SongTimeFormat;
|
||||||
* It also receives script events; scripted classes which extend this class
|
* It also receives script events; scripted classes which extend this class
|
||||||
* can be used to perform custom gameplay behaviors only on specific songs.
|
* can be used to perform custom gameplay behaviors only on specific songs.
|
||||||
*/
|
*/
|
||||||
class Song // implements IPlayStateScriptedClass
|
class Song implements IPlayStateScriptedClass
|
||||||
{
|
{
|
||||||
public final songId:String;
|
public final songId:String;
|
||||||
|
|
||||||
|
@ -29,6 +32,11 @@ class Song // implements IPlayStateScriptedClass
|
||||||
final variations:Array<String>;
|
final variations:Array<String>;
|
||||||
final difficulties:Map<String, SongDifficulty>;
|
final difficulties:Map<String, SongDifficulty>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to false if the song was edited in the charter and should not be saved as a high score.
|
||||||
|
*/
|
||||||
|
public var validScore:Bool = true;
|
||||||
|
|
||||||
var difficultyIds:Array<String>;
|
var difficultyIds:Array<String>;
|
||||||
|
|
||||||
public function new(id:String)
|
public function new(id:String)
|
||||||
|
@ -62,6 +70,9 @@ class Song // implements IPlayStateScriptedClass
|
||||||
// Variations may have different artist, time format, generatedBy, etc.
|
// Variations may have different artist, time format, generatedBy, etc.
|
||||||
for (metadata in _metadata)
|
for (metadata in _metadata)
|
||||||
{
|
{
|
||||||
|
// There may be more difficulties in the chart file than in the metadata,
|
||||||
|
// (i.e. non-playable charts like the one used for Pico on the speaker in Stress)
|
||||||
|
// but all the difficulties in the metadata must be in the chart file.
|
||||||
for (diffId in metadata.playData.difficulties)
|
for (diffId in metadata.playData.difficulties)
|
||||||
{
|
{
|
||||||
difficultyIds.push(diffId);
|
difficultyIds.push(diffId);
|
||||||
|
@ -75,7 +86,7 @@ class Song // implements IPlayStateScriptedClass
|
||||||
difficulty.timeFormat = metadata.timeFormat;
|
difficulty.timeFormat = metadata.timeFormat;
|
||||||
difficulty.divisions = metadata.divisions;
|
difficulty.divisions = metadata.divisions;
|
||||||
difficulty.timeChanges = metadata.timeChanges;
|
difficulty.timeChanges = metadata.timeChanges;
|
||||||
difficulty.loop = metadata.loop;
|
difficulty.looped = metadata.looped;
|
||||||
difficulty.generatedBy = metadata.generatedBy;
|
difficulty.generatedBy = metadata.generatedBy;
|
||||||
|
|
||||||
difficulty.stage = metadata.playData.stage;
|
difficulty.stage = metadata.playData.stage;
|
||||||
|
@ -116,8 +127,9 @@ class Song // implements IPlayStateScriptedClass
|
||||||
var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
|
var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
|
||||||
if (difficulty == null)
|
if (difficulty == null)
|
||||||
{
|
{
|
||||||
trace('Could not find difficulty $diffId for song $songId');
|
trace('Fabricated new difficulty for $diffId.');
|
||||||
continue;
|
difficulty = new SongDifficulty(this, diffId, variation);
|
||||||
|
difficulties.set(diffId, difficulty);
|
||||||
}
|
}
|
||||||
// Add the chart data to the difficulty.
|
// Add the chart data to the difficulty.
|
||||||
difficulty.notes = chartData.notes.get(diffId);
|
difficulty.notes = chartData.notes.get(diffId);
|
||||||
|
@ -166,6 +178,46 @@ class Song // implements IPlayStateScriptedClass
|
||||||
{
|
{
|
||||||
return 'Song($songId)';
|
return 'Song($songId)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function onPause(event:PauseScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onResume(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onSongLoaded(event:SongLoadScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onSongStart(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onSongEnd(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onGameOver(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onSongRetry(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onNoteHit(event:NoteScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onNoteMiss(event:NoteScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onNoteGhostMiss(event:GhostMissNoteScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onSongEvent(event:SongEventScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onStepHit(event:SongTimeScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onBeatHit(event:SongTimeScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCountdownStart(event:CountdownScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCountdownStep(event:CountdownScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCountdownEnd(event:CountdownScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onScriptEvent(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onCreate(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onDestroy(event:ScriptEvent):Void {};
|
||||||
|
|
||||||
|
public function onUpdate(event:UpdateScriptEvent):Void {};
|
||||||
}
|
}
|
||||||
|
|
||||||
class SongDifficulty
|
class SongDifficulty
|
||||||
|
@ -199,7 +251,7 @@ class SongDifficulty
|
||||||
public var songArtist:String = SongValidator.DEFAULT_ARTIST;
|
public var songArtist:String = SongValidator.DEFAULT_ARTIST;
|
||||||
public var timeFormat:SongTimeFormat = SongValidator.DEFAULT_TIMEFORMAT;
|
public var timeFormat:SongTimeFormat = SongValidator.DEFAULT_TIMEFORMAT;
|
||||||
public var divisions:Int = SongValidator.DEFAULT_DIVISIONS;
|
public var divisions:Int = SongValidator.DEFAULT_DIVISIONS;
|
||||||
public var loop:Bool = SongValidator.DEFAULT_LOOP;
|
public var looped:Bool = SongValidator.DEFAULT_LOOPED;
|
||||||
public var generatedBy:String = SongValidator.DEFAULT_GENERATEDBY;
|
public var generatedBy:String = SongValidator.DEFAULT_GENERATEDBY;
|
||||||
|
|
||||||
public var timeChanges:Array<SongTimeChange> = [];
|
public var timeChanges:Array<SongTimeChange> = [];
|
||||||
|
@ -246,32 +298,112 @@ class SongDifficulty
|
||||||
return cast events;
|
return cast events;
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function cacheInst()
|
public inline function cacheInst():Void
|
||||||
{
|
{
|
||||||
FlxG.sound.cache(Paths.inst(this.song.songId));
|
FlxG.sound.cache(Paths.inst(this.song.songId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function playInst(volume:Float = 1.0, looped:Bool = false)
|
public inline function playInst(volume:Float = 1.0, looped:Bool = false):Void
|
||||||
{
|
{
|
||||||
var suffix:String = variation == null ? null : '-$variation';
|
var suffix:String = (variation ?? '') != '' ? '-$variation' : '';
|
||||||
FlxG.sound.playMusic(Paths.inst(this.song.songId, suffix), volume, looped);
|
FlxG.sound.playMusic(Paths.inst(this.song.songId, suffix), volume, looped);
|
||||||
}
|
}
|
||||||
|
|
||||||
public inline function cacheVocals()
|
/**
|
||||||
|
* Cache the vocals for a given character.
|
||||||
|
* @param id The character we are about to play.
|
||||||
|
*/
|
||||||
|
public inline function cacheVocals(?id:String = 'bf'):Void
|
||||||
{
|
{
|
||||||
FlxG.sound.cache(Paths.voices(this.song.songId));
|
for (voice in buildVoiceList(id))
|
||||||
|
{
|
||||||
|
FlxG.sound.cache(voice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildVoiceList():Array<String>
|
/**
|
||||||
|
* Build a list of vocal files for the given character.
|
||||||
|
* Automatically resolves suffixed character IDs (so bf-car will resolve to bf if needed).
|
||||||
|
*
|
||||||
|
* @param id The character we are about to play.
|
||||||
|
*/
|
||||||
|
public function buildVoiceList(?id:String = 'bf'):Array<String>
|
||||||
{
|
{
|
||||||
// TODO: Implement.
|
var playableCharData:SongPlayableChar = getPlayableChar(id);
|
||||||
|
if (playableCharData == null)
|
||||||
return [variation == null ? '' : '-$variation'];
|
{
|
||||||
|
trace('Could not find playable char $id for song ${this.song.songId}');
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildVocals(charId:String = "bf"):VoicesGroup
|
var suffix:String = (variation ?? '') != '' ? '-$variation' : '';
|
||||||
|
|
||||||
|
// Automatically resolve voices by removing suffixes.
|
||||||
|
// For example, if `Voices-bf-car.ogg` does not exist, check for `Voices-bf.ogg`.
|
||||||
|
|
||||||
|
var playerId:String = id;
|
||||||
|
var voicePlayer:String = Paths.voices(this.song.songId, '-$id$suffix');
|
||||||
|
while (voicePlayer != null && !Assets.exists(voicePlayer))
|
||||||
{
|
{
|
||||||
var result:VoicesGroup = VoicesGroup.build(this.song.songId, this.buildVoiceList());
|
// Remove the last suffix.
|
||||||
|
// For example, bf-car becomes bf.
|
||||||
|
playerId = playerId.split('-').slice(0, -1).join('-');
|
||||||
|
// Try again.
|
||||||
|
voicePlayer = playerId == '' ? null : Paths.voices(this.song.songId, '-${playerId}$suffix');
|
||||||
|
}
|
||||||
|
|
||||||
|
var opponentId:String = playableCharData.opponent;
|
||||||
|
var voiceOpponent:String = Paths.voices(this.song.songId, '-${opponentId}$suffix');
|
||||||
|
while (voiceOpponent != null && !Assets.exists(voiceOpponent))
|
||||||
|
{
|
||||||
|
// Remove the last suffix.
|
||||||
|
opponentId = opponentId.split('-').slice(0, -1).join('-');
|
||||||
|
// Try again.
|
||||||
|
voiceOpponent = opponentId == '' ? null : Paths.voices(this.song.songId, '-${opponentId}$suffix');
|
||||||
|
}
|
||||||
|
|
||||||
|
var result:Array<String> = [];
|
||||||
|
if (voicePlayer != null) result.push(voicePlayer);
|
||||||
|
if (voiceOpponent != null) result.push(voiceOpponent);
|
||||||
|
if (voicePlayer == null && voiceOpponent == null)
|
||||||
|
{
|
||||||
|
// Try to use `Voices.ogg` if no other voices are found.
|
||||||
|
if (Assets.exists(Paths.voices(this.song.songId, ''))) result.push(Paths.voices(this.song.songId, '$suffix'));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a VoicesGroup, an audio object that can play the vocals for all characters.
|
||||||
|
* @param charId The player ID.
|
||||||
|
* @return The generated vocal group.
|
||||||
|
*/
|
||||||
|
public function buildVocals(charId:String = 'bf'):VoicesGroup
|
||||||
|
{
|
||||||
|
var result:VoicesGroup = new VoicesGroup();
|
||||||
|
|
||||||
|
var voiceList:Array<String> = buildVoiceList(charId);
|
||||||
|
|
||||||
|
if (voiceList.length == 0)
|
||||||
|
{
|
||||||
|
trace('Could not find any voices for song ${this.song.songId}');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add player vocals.
|
||||||
|
if (voiceList[0] != null) result.addPlayerVoice(new FlxSound().loadEmbedded(Assets.getSound(voiceList[0])));
|
||||||
|
// Add opponent vocals.
|
||||||
|
if (voiceList[1] != null) result.addOpponentVoice(new FlxSound().loadEmbedded(Assets.getSound(voiceList[1])));
|
||||||
|
|
||||||
|
// Add additional vocals.
|
||||||
|
if (voiceList.length > 2)
|
||||||
|
{
|
||||||
|
for (i in 2...voiceList.length)
|
||||||
|
{
|
||||||
|
result.add(new FlxSound().loadEmbedded(Assets.getSound(voiceList[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,7 @@ typedef RawSongMetadata =
|
||||||
var timeFormat:SongTimeFormat;
|
var timeFormat:SongTimeFormat;
|
||||||
var divisions:Int;
|
var divisions:Int;
|
||||||
var timeChanges:Array<SongTimeChange>;
|
var timeChanges:Array<SongTimeChange>;
|
||||||
var loop:Bool;
|
var looped:Bool;
|
||||||
var playData:SongPlayData;
|
var playData:SongPlayData;
|
||||||
var generatedBy:String;
|
var generatedBy:String;
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ abstract SongMetadata(RawSongMetadata)
|
||||||
timeFormat: 'ms',
|
timeFormat: 'ms',
|
||||||
divisions: 96,
|
divisions: 96,
|
||||||
timeChanges: [new SongTimeChange(-1, 0, 100, 4, 4, [4, 4, 4, 4])],
|
timeChanges: [new SongTimeChange(-1, 0, 100, 4, 4, [4, 4, 4, 4])],
|
||||||
loop: false,
|
looped: false,
|
||||||
playData:
|
playData:
|
||||||
{
|
{
|
||||||
songVariations: [],
|
songVariations: [],
|
||||||
|
@ -277,7 +277,7 @@ abstract SongMetadata(RawSongMetadata)
|
||||||
result.timeFormat = this.timeFormat;
|
result.timeFormat = this.timeFormat;
|
||||||
result.divisions = this.divisions;
|
result.divisions = this.divisions;
|
||||||
result.timeChanges = this.timeChanges;
|
result.timeChanges = this.timeChanges;
|
||||||
result.loop = this.loop;
|
result.looped = this.looped;
|
||||||
result.playData = this.playData;
|
result.playData = this.playData;
|
||||||
result.generatedBy = this.generatedBy;
|
result.generatedBy = this.generatedBy;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class SongValidator
|
||||||
public static final DEFAULT_ARTIST:String = "Unknown";
|
public static final DEFAULT_ARTIST:String = "Unknown";
|
||||||
public static final DEFAULT_TIMEFORMAT:SongTimeFormat = SongTimeFormat.MILLISECONDS;
|
public static final DEFAULT_TIMEFORMAT:SongTimeFormat = SongTimeFormat.MILLISECONDS;
|
||||||
public static final DEFAULT_DIVISIONS:Int = -1;
|
public static final DEFAULT_DIVISIONS:Int = -1;
|
||||||
public static final DEFAULT_LOOP:Bool = false;
|
public static final DEFAULT_LOOPED:Bool = false;
|
||||||
public static final DEFAULT_STAGE:String = "mainStage";
|
public static final DEFAULT_STAGE:String = "mainStage";
|
||||||
public static final DEFAULT_SCROLLSPEED:Float = 1.0;
|
public static final DEFAULT_SCROLLSPEED:Float = 1.0;
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import flixel.graphics.frames.FlxAtlasFrames;
|
||||||
import flixel.graphics.frames.FlxFrame;
|
import flixel.graphics.frames.FlxFrame;
|
||||||
import flixel.group.FlxGroup;
|
import flixel.group.FlxGroup;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSpriteUtil;
|
import flixel.util.FlxSpriteUtil;
|
||||||
|
@ -76,8 +76,7 @@ class DebugBoundingState extends FlxState
|
||||||
|
|
||||||
// uiStuff.findComponent("btnViewSpriteSheet").onClick = _ -> curView = SPRITESHEET;
|
// uiStuff.findComponent("btnViewSpriteSheet").onClick = _ -> curView = SPRITESHEET;
|
||||||
var dropdown:DropDown = cast uiStuff.findComponent("swapper");
|
var dropdown:DropDown = cast uiStuff.findComponent("swapper");
|
||||||
dropdown.onChange = function(e:UIEvent)
|
dropdown.onChange = function(e:UIEvent) {
|
||||||
{
|
|
||||||
trace(e.type);
|
trace(e.type);
|
||||||
curView = cast e.data.curView;
|
curView = cast e.data.curView;
|
||||||
trace(e.data);
|
trace(e.data);
|
||||||
|
@ -147,8 +146,7 @@ class DebugBoundingState extends FlxState
|
||||||
swagOutlines.antialiasing = true;
|
swagOutlines.antialiasing = true;
|
||||||
spriteSheetView.add(swagOutlines);
|
spriteSheetView.add(swagOutlines);
|
||||||
|
|
||||||
FlxG.stage.window.onDropFile.add(function(path:String)
|
FlxG.stage.window.onDropFile.add(function(path:String) {
|
||||||
{
|
|
||||||
// WACKY ASS TESTING SHIT FOR WEB FILE LOADING??
|
// WACKY ASS TESTING SHIT FOR WEB FILE LOADING??
|
||||||
#if web
|
#if web
|
||||||
var swagList:FileList = cast path;
|
var swagList:FileList = cast path;
|
||||||
|
@ -157,8 +155,7 @@ class DebugBoundingState extends FlxState
|
||||||
trace(objShit);
|
trace(objShit);
|
||||||
|
|
||||||
var funnysound = new FlxSound().loadStream('https://cdn.discordapp.com/attachments/767500676166451231/817821618251759666/Flutter.mp3', false, false,
|
var funnysound = new FlxSound().loadStream('https://cdn.discordapp.com/attachments/767500676166451231/817821618251759666/Flutter.mp3', false, false,
|
||||||
null, function()
|
null, function() {
|
||||||
{
|
|
||||||
trace('LOADED SHIT??');
|
trace('LOADED SHIT??');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,8 +164,7 @@ class DebugBoundingState extends FlxState
|
||||||
|
|
||||||
var urlShit = new URLLoader(new URLRequest(objShit));
|
var urlShit = new URLLoader(new URLRequest(objShit));
|
||||||
|
|
||||||
new FlxTimer().start(3, function(tmr:FlxTimer)
|
new FlxTimer().start(3, function(tmr:FlxTimer) {
|
||||||
{
|
|
||||||
// music lol!
|
// music lol!
|
||||||
if (urlShit.dataFormat == BINARY)
|
if (urlShit.dataFormat == BINARY)
|
||||||
{
|
{
|
||||||
|
@ -255,8 +251,7 @@ class DebugBoundingState extends FlxState
|
||||||
charDropdown.dataSource.add({text: char});
|
charDropdown.dataSource.add({text: char});
|
||||||
}
|
}
|
||||||
|
|
||||||
charDropdown.onChange = function(e:UIEvent)
|
charDropdown.onChange = function(e:UIEvent) {
|
||||||
{
|
|
||||||
loadAnimShit(e.data.text);
|
loadAnimShit(e.data.text);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -306,8 +301,7 @@ class DebugBoundingState extends FlxState
|
||||||
if (!LimeAssets.libraryPaths.exists(library)) throw "Missing library: " + library;
|
if (!LimeAssets.libraryPaths.exists(library)) throw "Missing library: " + library;
|
||||||
|
|
||||||
// var callback = callbacks.add("library:" + library);
|
// var callback = callbacks.add("library:" + library);
|
||||||
Assets.loadLibrary(library).onComplete(function(_)
|
Assets.loadLibrary(library).onComplete(function(_) {
|
||||||
{
|
|
||||||
trace('LOADED... awesomeness...');
|
trace('LOADED... awesomeness...');
|
||||||
// callback();
|
// callback();
|
||||||
});
|
});
|
||||||
|
@ -483,8 +477,7 @@ class DebugBoundingState extends FlxState
|
||||||
}
|
}
|
||||||
|
|
||||||
animDropDownMenu.setData(FlxUIDropDownMenu.makeStrIdLabelArray(animThing, true));
|
animDropDownMenu.setData(FlxUIDropDownMenu.makeStrIdLabelArray(animThing, true));
|
||||||
animDropDownMenu.callback = function(str:String)
|
animDropDownMenu.callback = function(str:String) {
|
||||||
{
|
|
||||||
// clears the canvas
|
// clears the canvas
|
||||||
onionSkinChar.pixels.fillRect(new Rectangle(0, 0, FlxG.width * 2, FlxG.height * 2), 0x00000000);
|
onionSkinChar.pixels.fillRect(new Rectangle(0, 0, FlxG.width * 2, FlxG.height * 2), 0x00000000);
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,12 @@ import flixel.FlxSprite;
|
||||||
import flixel.group.FlxSpriteGroup;
|
import flixel.group.FlxSpriteGroup;
|
||||||
import flixel.math.FlxPoint;
|
import flixel.math.FlxPoint;
|
||||||
import flixel.math.FlxRect;
|
import flixel.math.FlxRect;
|
||||||
import flixel.system.FlxSound;
|
import flixel.sound.FlxSound;
|
||||||
import flixel.util.FlxColor;
|
import flixel.util.FlxColor;
|
||||||
import flixel.util.FlxSort;
|
import flixel.util.FlxSort;
|
||||||
import flixel.util.FlxTimer;
|
import flixel.util.FlxTimer;
|
||||||
import funkin.audio.visualize.PolygonSpectogram;
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
import funkin.audio.VocalGroup;
|
import funkin.audio.VoicesGroup;
|
||||||
import funkin.input.Cursor;
|
import funkin.input.Cursor;
|
||||||
import funkin.modding.events.ScriptEvent;
|
import funkin.modding.events.ScriptEvent;
|
||||||
import funkin.play.HealthIcon;
|
import funkin.play.HealthIcon;
|
||||||
|
@ -596,14 +596,14 @@ class ChartEditorState extends HaxeUIState
|
||||||
/**
|
/**
|
||||||
* The audio track for the vocals.
|
* The audio track for the vocals.
|
||||||
*/
|
*/
|
||||||
var audioVocalTrackGroup:VocalGroup;
|
var audioVocalTrackGroup:VoicesGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of the audio tracks for each character's vocals.
|
* A map of the audio tracks for each character's vocals.
|
||||||
* - Keys are the character IDs.
|
* - Keys are the character IDs.
|
||||||
* - Values are the FlxSound objects to play that character's vocals.
|
* - Values are the FlxSound objects to play that character's vocals.
|
||||||
*
|
*
|
||||||
* When switching characters, the elements of the VocalGroup will be swapped to match the new character.
|
* When switching characters, the elements of the VoicesGroup will be swapped to match the new character.
|
||||||
*/
|
*/
|
||||||
var audioVocalTracks:Map<String, FlxSound> = new Map<String, FlxSound>();
|
var audioVocalTracks:Map<String, FlxSound> = new Map<String, FlxSound>();
|
||||||
|
|
||||||
|
@ -961,7 +961,7 @@ class ChartEditorState extends HaxeUIState
|
||||||
// Initialize the song chart data.
|
// Initialize the song chart data.
|
||||||
songChartData = new Map<String, SongChartData>();
|
songChartData = new Map<String, SongChartData>();
|
||||||
|
|
||||||
audioVocalTrackGroup = new VocalGroup();
|
audioVocalTrackGroup = new VoicesGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue