mirror of
https://github.com/ninjamuffin99/Funkin.git
synced 2025-07-03 17:16:43 +00:00
Merge pull request #240 from FunkinCrew/feature/chart-waveform
Feature/chart waveform
This commit is contained in:
commit
18ffb9fc36
|
@ -16,6 +16,7 @@ class PolygonSpectogram extends MeshRender
|
||||||
public var visType:VISTYPE = UPDATED;
|
public var visType:VISTYPE = UPDATED;
|
||||||
public var daHeight:Float = FlxG.height;
|
public var daHeight:Float = FlxG.height;
|
||||||
public var realtimeVisLenght:Float = 0.2;
|
public var realtimeVisLenght:Float = 0.2;
|
||||||
|
public var realtimeStartOffset:Float = 0;
|
||||||
|
|
||||||
var numSamples:Int = 0;
|
var numSamples:Int = 0;
|
||||||
var setBuffer:Bool = false;
|
var setBuffer:Bool = false;
|
||||||
|
@ -26,11 +27,11 @@ class PolygonSpectogram extends MeshRender
|
||||||
public var thickness:Float = 2;
|
public var thickness:Float = 2;
|
||||||
public var waveAmplitude:Int = 100;
|
public var waveAmplitude:Int = 100;
|
||||||
|
|
||||||
public function new(daSound:FlxSound, ?col:FlxColor = FlxColor.WHITE, ?height:Float = 720, ?detail:Float = 1)
|
public function new(?daSound:FlxSound, ?col:FlxColor = FlxColor.WHITE, ?height:Float = 720, ?detail:Float = 1)
|
||||||
{
|
{
|
||||||
super(0, 0, col);
|
super(0, 0, col);
|
||||||
|
|
||||||
setSound(daSound);
|
if (daSound != null) setSound(daSound);
|
||||||
|
|
||||||
if (height != null) this.daHeight = height;
|
if (height != null) this.daHeight = height;
|
||||||
|
|
||||||
|
@ -73,13 +74,20 @@ class PolygonSpectogram extends MeshRender
|
||||||
|
|
||||||
start = Math.max(start, 0);
|
start = Math.max(start, 0);
|
||||||
|
|
||||||
|
// gets how many samples to generate
|
||||||
var samplesToGen:Int = Std.int(sampleRate * seconds);
|
var samplesToGen:Int = Std.int(sampleRate * seconds);
|
||||||
|
|
||||||
|
if (samplesToGen == 0) return;
|
||||||
// gets which sample to start at
|
// gets which sample to start at
|
||||||
var startSample:Int = Std.int(FlxMath.remapToRange(start, 0, vis.snd.length, 0, numSamples));
|
var startSample:Int = Std.int(FlxMath.remapToRange(start, 0, vis.snd.length, 0, numSamples));
|
||||||
|
|
||||||
|
// Check if startSample and samplesToGen are within the bounds of the audioData array
|
||||||
|
if (startSample < 0 || startSample >= numSamples) return;
|
||||||
|
if (samplesToGen <= 0 || startSample + samplesToGen > numSamples) samplesToGen = numSamples - startSample;
|
||||||
|
|
||||||
var prevPoint:FlxPoint = new FlxPoint();
|
var prevPoint:FlxPoint = new FlxPoint();
|
||||||
|
|
||||||
var funnyPixels:Int = Std.int(daHeight); // sorta redundant but just need it for different var...
|
var funnyPixels:Int = Std.int(daHeight * detail); // sorta redundant but just need it for different var...
|
||||||
|
|
||||||
if (prevAudioData == audioData.subarray(startSample, startSample + samplesToGen)) return; // optimize / finish funciton here, no need to re-render
|
if (prevAudioData == audioData.subarray(startSample, startSample + samplesToGen)) return; // optimize / finish funciton here, no need to re-render
|
||||||
|
|
||||||
|
@ -123,7 +131,7 @@ class PolygonSpectogram extends MeshRender
|
||||||
|
|
||||||
curTime = vis.snd.time;
|
curTime = vis.snd.time;
|
||||||
|
|
||||||
generateSection(vis.snd.time, realtimeVisLenght);
|
if (vis.snd.time < vis.snd.length - realtimeVisLenght) generateSection(vis.snd.time + realtimeStartOffset, realtimeVisLenght);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
71
source/funkin/audio/visualize/PolygonVisGroup.hx
Normal file
71
source/funkin/audio/visualize/PolygonVisGroup.hx
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
package funkin.audio.visualize;
|
||||||
|
|
||||||
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import flixel.sound.FlxSound;
|
||||||
|
|
||||||
|
class PolygonVisGroup extends FlxTypedGroup<PolygonSpectogram>
|
||||||
|
{
|
||||||
|
public var playerVis:PolygonSpectogram;
|
||||||
|
public var opponentVis:PolygonSpectogram;
|
||||||
|
|
||||||
|
var instVis:PolygonSpectogram;
|
||||||
|
|
||||||
|
public function new()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
playerVis = new PolygonSpectogram();
|
||||||
|
opponentVis = new PolygonSpectogram();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the player's visualizer to the group.
|
||||||
|
* @param visSnd The visualizer to add.
|
||||||
|
*/
|
||||||
|
public function addPlayerVis(visSnd:FlxSound):Void
|
||||||
|
{
|
||||||
|
var vis:PolygonSpectogram = new PolygonSpectogram(visSnd);
|
||||||
|
super.add(vis);
|
||||||
|
playerVis = vis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the opponent's visualizer to the group.
|
||||||
|
* @param visSnd The visualizer to add.
|
||||||
|
*/
|
||||||
|
public function addOpponentVis(visSnd:FlxSound):Void
|
||||||
|
{
|
||||||
|
var vis:PolygonSpectogram = new PolygonSpectogram(visSnd);
|
||||||
|
super.add(vis);
|
||||||
|
opponentVis = vis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the instrument's visualizer to the group.
|
||||||
|
* @param visSnd The visualizer to add.
|
||||||
|
*/
|
||||||
|
public function addInstVis(visSnd:FlxSound):Void
|
||||||
|
{
|
||||||
|
var vis:PolygonSpectogram = new PolygonSpectogram(visSnd);
|
||||||
|
super.add(vis);
|
||||||
|
instVis = vis;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overrides the add function to add a visualizer to the group.
|
||||||
|
* @param vis The visualizer to add.
|
||||||
|
* @return The added visualizer.
|
||||||
|
*/
|
||||||
|
public override function add(vis:PolygonSpectogram):PolygonSpectogram
|
||||||
|
{
|
||||||
|
var result:PolygonSpectogram = super.add(vis);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override function destroy():Void
|
||||||
|
{
|
||||||
|
playerVis.destroy();
|
||||||
|
opponentVis.destroy();
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
}
|
|
@ -119,6 +119,9 @@ import haxe.ui.events.UIEvent;
|
||||||
import haxe.ui.events.UIEvent;
|
import haxe.ui.events.UIEvent;
|
||||||
import haxe.ui.focus.FocusManager;
|
import haxe.ui.focus.FocusManager;
|
||||||
import openfl.display.BitmapData;
|
import openfl.display.BitmapData;
|
||||||
|
import funkin.audio.visualize.PolygonSpectogram;
|
||||||
|
import flixel.group.FlxGroup.FlxTypedGroup;
|
||||||
|
import funkin.audio.visualize.PolygonVisGroup;
|
||||||
import flixel.input.mouse.FlxMouseEvent;
|
import flixel.input.mouse.FlxMouseEvent;
|
||||||
import flixel.text.FlxText;
|
import flixel.text.FlxText;
|
||||||
|
|
||||||
|
@ -341,6 +344,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
gridTiledSprite.y = -scrollPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD);
|
gridTiledSprite.y = -scrollPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD);
|
||||||
gridPlayheadScrollArea.y = gridTiledSprite.y;
|
gridPlayheadScrollArea.y = gridTiledSprite.y;
|
||||||
|
|
||||||
|
if (audioVisGroup != null && audioVisGroup.playerVis != null)
|
||||||
|
{
|
||||||
|
audioVisGroup.playerVis.y = Math.max(gridTiledSprite.y, MENU_BAR_HEIGHT);
|
||||||
|
}
|
||||||
|
if (audioVisGroup != null && audioVisGroup.opponentVis != null)
|
||||||
|
{
|
||||||
|
audioVisGroup.opponentVis.y = Math.max(gridTiledSprite.y, MENU_BAR_HEIGHT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,12 +451,16 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
|
|
||||||
function get_playheadPositionInMs():Float
|
function get_playheadPositionInMs():Float
|
||||||
{
|
{
|
||||||
|
if (audioVisGroup != null && audioVisGroup.playerVis != null)
|
||||||
|
audioVisGroup.playerVis.realtimeStartOffset = -Conductor.getStepTimeInMs(playheadPositionInSteps);
|
||||||
return Conductor.getStepTimeInMs(playheadPositionInSteps);
|
return Conductor.getStepTimeInMs(playheadPositionInSteps);
|
||||||
}
|
}
|
||||||
|
|
||||||
function set_playheadPositionInMs(value:Float):Float
|
function set_playheadPositionInMs(value:Float):Float
|
||||||
{
|
{
|
||||||
playheadPositionInSteps = Conductor.getTimeInSteps(value);
|
playheadPositionInSteps = Conductor.getTimeInSteps(value);
|
||||||
|
|
||||||
|
if (audioVisGroup != null && audioVisGroup.playerVis != null) audioVisGroup.playerVis.realtimeStartOffset = -value;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,6 +963,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
var audioVocalTrackGroup:Null<VoicesGroup> = null;
|
var audioVocalTrackGroup:Null<VoicesGroup> = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The audio vis for the inst/vocals.
|
||||||
|
* `null` until vocal track(s) are loaded.
|
||||||
|
* When switching characters, the elements of the PolygonVisGroup will be swapped to match the new character.
|
||||||
|
*/
|
||||||
|
var audioVisGroup:Null<PolygonVisGroup> = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of the audio tracks for each character's vocals.
|
* A map of the audio tracks for each character's vocals.
|
||||||
* - Keys are `characterId-variation` (with `characterId` being the default variation).
|
* - Keys are `characterId-variation` (with `characterId` being the default variation).
|
||||||
|
@ -1568,6 +1591,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
*/
|
*/
|
||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The group containing the visulizers! */
|
||||||
|
var visulizerGrps:FlxTypedGroup<PolygonSpectogram> = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IMAGE used for the grid. Updated by ChartEditorThemeHandler.
|
* The IMAGE used for the grid. Updated by ChartEditorThemeHandler.
|
||||||
*/
|
*/
|
||||||
|
@ -2041,6 +2068,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
menuBG.zIndex = -100;
|
menuBG.zIndex = -100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oppSpectogram:PolygonSpectogram;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds and displays the chart editor grid, including the playhead and cursor.
|
* Builds and displays the chart editor grid, including the playhead and cursor.
|
||||||
*/
|
*/
|
||||||
|
@ -2116,6 +2145,9 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
healthIconBF.flipX = true;
|
healthIconBF.flipX = true;
|
||||||
add(healthIconBF);
|
add(healthIconBF);
|
||||||
healthIconBF.zIndex = 30;
|
healthIconBF.zIndex = 30;
|
||||||
|
|
||||||
|
audioVisGroup = new PolygonVisGroup();
|
||||||
|
add(audioVisGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildNotePreview():Void
|
function buildNotePreview():Void
|
||||||
|
@ -4147,10 +4179,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
|
||||||
{
|
{
|
||||||
targetCursorMode = Cell;
|
targetCursorMode = Cell;
|
||||||
}
|
}
|
||||||
}
|
else if (overlapsHealthIcons)
|
||||||
else if (overlapsHealthIcons)
|
{
|
||||||
{
|
targetCursorMode = Pointer;
|
||||||
targetCursorMode = Pointer;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package funkin.ui.debug.charting.handlers;
|
||||||
import flixel.system.FlxAssets.FlxSoundAsset;
|
import flixel.system.FlxAssets.FlxSoundAsset;
|
||||||
import flixel.system.FlxSound;
|
import flixel.system.FlxSound;
|
||||||
import funkin.audio.VoicesGroup;
|
import funkin.audio.VoicesGroup;
|
||||||
|
import funkin.audio.visualize.PolygonVisGroup;
|
||||||
import funkin.audio.FunkinSound;
|
import funkin.audio.FunkinSound;
|
||||||
import funkin.play.character.BaseCharacter.CharacterType;
|
import funkin.play.character.BaseCharacter.CharacterType;
|
||||||
import funkin.util.FileUtil;
|
import funkin.util.FileUtil;
|
||||||
|
@ -171,6 +172,7 @@ class ChartEditorAudioHandler
|
||||||
var vocalTrack:Null<FunkinSound> = SoundUtil.buildSoundFromBytes(vocalTrackData);
|
var vocalTrack:Null<FunkinSound> = SoundUtil.buildSoundFromBytes(vocalTrackData);
|
||||||
|
|
||||||
if (state.audioVocalTrackGroup == null) state.audioVocalTrackGroup = new VoicesGroup();
|
if (state.audioVocalTrackGroup == null) state.audioVocalTrackGroup = new VoicesGroup();
|
||||||
|
if (state.audioVisGroup == null) state.audioVisGroup = new PolygonVisGroup();
|
||||||
|
|
||||||
if (vocalTrack != null)
|
if (vocalTrack != null)
|
||||||
{
|
{
|
||||||
|
@ -178,11 +180,25 @@ class ChartEditorAudioHandler
|
||||||
{
|
{
|
||||||
case BF:
|
case BF:
|
||||||
state.audioVocalTrackGroup.addPlayerVoice(vocalTrack);
|
state.audioVocalTrackGroup.addPlayerVoice(vocalTrack);
|
||||||
|
state.audioVisGroup.addPlayerVis(vocalTrack);
|
||||||
|
state.audioVisGroup.playerVis.x = 885;
|
||||||
|
state.audioVisGroup.playerVis.realtimeVisLenght = Conductor.getStepTimeInMs(16) * 0.00195;
|
||||||
|
state.audioVisGroup.playerVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
||||||
|
state.audioVisGroup.playerVis.detail = 1;
|
||||||
|
|
||||||
state.audioVocalTrackGroup.playerVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
state.audioVocalTrackGroup.playerVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||||
return true;
|
return true;
|
||||||
case DAD:
|
case DAD:
|
||||||
state.audioVocalTrackGroup.addOpponentVoice(vocalTrack);
|
state.audioVocalTrackGroup.addOpponentVoice(vocalTrack);
|
||||||
|
state.audioVisGroup.addOpponentVis(vocalTrack);
|
||||||
|
state.audioVisGroup.opponentVis.x = 435;
|
||||||
|
|
||||||
|
state.audioVisGroup.opponentVis.realtimeVisLenght = Conductor.getStepTimeInMs(16) * 0.00195;
|
||||||
|
state.audioVisGroup.opponentVis.daHeight = (ChartEditorState.GRID_SIZE) * 16;
|
||||||
|
state.audioVisGroup.opponentVis.detail = 1;
|
||||||
|
|
||||||
state.audioVocalTrackGroup.opponentVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
state.audioVocalTrackGroup.opponentVoicesOffset = state.currentSongOffsets.getVocalOffset(charId);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
case OTHER:
|
case OTHER:
|
||||||
state.audioVocalTrackGroup.add(vocalTrack);
|
state.audioVocalTrackGroup.add(vocalTrack);
|
||||||
|
|
Loading…
Reference in a new issue