diff --git a/source/funkin/audio/visualize/PolygonSpectogram.hx b/source/funkin/audio/visualize/PolygonSpectogram.hx index 604bc910b..37a6c15d1 100644 --- a/source/funkin/audio/visualize/PolygonSpectogram.hx +++ b/source/funkin/audio/visualize/PolygonSpectogram.hx @@ -16,6 +16,7 @@ class PolygonSpectogram extends MeshRender public var visType:VISTYPE = UPDATED; public var daHeight:Float = FlxG.height; public var realtimeVisLenght:Float = 0.2; + public var realtimeStartOffset:Float = 0; var numSamples:Int = 0; var setBuffer:Bool = false; @@ -26,11 +27,11 @@ class PolygonSpectogram extends MeshRender public var thickness:Float = 2; 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); - setSound(daSound); + if (daSound != null) setSound(daSound); if (height != null) this.daHeight = height; @@ -73,13 +74,20 @@ class PolygonSpectogram extends MeshRender start = Math.max(start, 0); + // gets how many samples to generate var samplesToGen:Int = Std.int(sampleRate * seconds); + + if (samplesToGen == 0) return; // gets which sample to start at 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 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 @@ -123,7 +131,7 @@ class PolygonSpectogram extends MeshRender curTime = vis.snd.time; - generateSection(vis.snd.time, realtimeVisLenght); + if (vis.snd.time < vis.snd.length - realtimeVisLenght) generateSection(vis.snd.time + realtimeStartOffset, realtimeVisLenght); } } } diff --git a/source/funkin/audio/visualize/PolygonVisGroup.hx b/source/funkin/audio/visualize/PolygonVisGroup.hx new file mode 100644 index 000000000..2903eaccd --- /dev/null +++ b/source/funkin/audio/visualize/PolygonVisGroup.hx @@ -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 +{ + 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(); + } +} diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx index 3696369d4..78de08fdf 100644 --- a/source/funkin/ui/debug/charting/ChartEditorState.hx +++ b/source/funkin/ui/debug/charting/ChartEditorState.hx @@ -119,6 +119,9 @@ import haxe.ui.events.UIEvent; import haxe.ui.events.UIEvent; import haxe.ui.focus.FocusManager; 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.text.FlxText; @@ -341,6 +344,15 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { gridTiledSprite.y = -scrollPositionInPixels + (MENU_BAR_HEIGHT + GRID_TOP_PAD); 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 { + if (audioVisGroup != null && audioVisGroup.playerVis != null) + audioVisGroup.playerVis.realtimeStartOffset = -Conductor.getStepTimeInMs(playheadPositionInSteps); return Conductor.getStepTimeInMs(playheadPositionInSteps); } function set_playheadPositionInMs(value:Float):Float { playheadPositionInSteps = Conductor.getTimeInSteps(value); + + if (audioVisGroup != null && audioVisGroup.playerVis != null) audioVisGroup.playerVis.realtimeStartOffset = -value; return value; } @@ -947,6 +963,13 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState */ var audioVocalTrackGroup:Null = 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 = null; + /** * A map of the audio tracks for each character's vocals. * - 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 = null; + /** * The IMAGE used for the grid. Updated by ChartEditorThemeHandler. */ @@ -2041,6 +2068,8 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState menuBG.zIndex = -100; } + var oppSpectogram:PolygonSpectogram; + /** * 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; add(healthIconBF); healthIconBF.zIndex = 30; + + audioVisGroup = new PolygonVisGroup(); + add(audioVisGroup); } function buildNotePreview():Void @@ -4147,10 +4179,10 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState { targetCursorMode = Cell; } - } - else if (overlapsHealthIcons) - { - targetCursorMode = Pointer; + else if (overlapsHealthIcons) + { + targetCursorMode = Pointer; + } } } } diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx index 2e62ecd00..272291a94 100644 --- a/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx +++ b/source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx @@ -3,6 +3,7 @@ package funkin.ui.debug.charting.handlers; import flixel.system.FlxAssets.FlxSoundAsset; import flixel.system.FlxSound; import funkin.audio.VoicesGroup; +import funkin.audio.visualize.PolygonVisGroup; import funkin.audio.FunkinSound; import funkin.play.character.BaseCharacter.CharacterType; import funkin.util.FileUtil; @@ -171,6 +172,7 @@ class ChartEditorAudioHandler var vocalTrack:Null = SoundUtil.buildSoundFromBytes(vocalTrackData); if (state.audioVocalTrackGroup == null) state.audioVocalTrackGroup = new VoicesGroup(); + if (state.audioVisGroup == null) state.audioVisGroup = new PolygonVisGroup(); if (vocalTrack != null) { @@ -178,11 +180,25 @@ class ChartEditorAudioHandler { case BF: 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); return true; case DAD: 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); + return true; case OTHER: state.audioVocalTrackGroup.add(vocalTrack);