Skip to content

Commit 1952709

Browse files
authored
Chart Editor all supported sound formats
Can now specify the extension of a music or sound file path. If none is passed, the default is used. Also makes waveform data nullable.
1 parent a12f848 commit 1952709

File tree

13 files changed

+86
-80
lines changed

13 files changed

+86
-80
lines changed

source/funkin/Paths.hx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,21 @@ class Paths implements ConsoleClass
112112
return getPath('$directory$key.srt', TEXT, library);
113113
}
114114

115-
public static function sound(key:String, ?library:String):String
115+
public static function sound(key:String, ?library:String, extension:String = ''):String
116116
{
117-
return getPath('sounds/$key.${Constants.EXT_SOUND}', SOUND, library);
117+
if (extension == '') extension = Constants.EXT_SOUND;
118+
return getPath('sounds/$key.${extension}', SOUND, library);
118119
}
119120

120-
public static function soundRandom(key:String, min:Int, max:Int, ?library:String):String
121+
public static function soundRandom(key:String, min:Int, max:Int, ?library:String, extension:String = ''):String
121122
{
122-
return sound(key + FlxG.random.int(min, max), library);
123+
return sound(key + FlxG.random.int(min, max), library, extension);
123124
}
124125

125-
public static function music(key:String, ?library:String):String
126+
public static function music(key:String, ?library:String, extension:String = ''):String
126127
{
127-
return getPath('music/$key.${Constants.EXT_SOUND}', MUSIC, library);
128+
if (extension == '') extension = Constants.EXT_SOUND;
129+
return getPath('music/$key.${extension}', MUSIC, library);
128130
}
129131

130132
public static function videos(key:String, ?library:String):String
@@ -139,24 +141,25 @@ class Paths implements ConsoleClass
139141
return getPath('videos/$key.${Constants.EXT_VIDEO}', BINARY, library ?? 'videos');
140142
}
141143

142-
public static function voices(song:String, ?suffix:String = ''):String
144+
public static function voices(song:String, ?suffix:String = '', extension:String = ''):String
143145
{
144-
if (suffix == null) suffix = ''; // no suffix, for a sorta backwards compatibility with older-ish voice files
145146

146-
return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${Constants.EXT_SOUND}';
147+
if (suffix == null) suffix = ''; // no suffix, for a sorta backwards compatibility with older-ish voice files
148+
if (extension == '') extension = Constants.EXT_SOUND;
149+
return 'songs:assets/songs/${song.toLowerCase()}/Voices$suffix.${extension}';
147150
}
148151

149152
/**
150153
* Gets the path to an `Inst.mp3/ogg` song instrumental from songs:assets/songs/`song`/
151154
* @param song name of the song to get instrumental for
152155
* @param suffix any suffix to add to end of song name, used for `-erect` variants usually
153-
* @param withExtension if it should return with the audio file extension `.mp3` or `.ogg`.
156+
* @param extension The audio file extension of the track. If empty, the default extension is passed.
154157
* @return String
155158
*/
156-
public static function inst(song:String, ?suffix:String = '', withExtension:Bool = true):String
159+
public static function inst(song:String, ?suffix:String = '', extension:String = ''):String
157160
{
158-
var ext:String = withExtension ? '.${Constants.EXT_SOUND}' : '';
159-
return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix$ext';
161+
if (extension == '') extension = Constants.EXT_SOUND;
162+
return 'songs:assets/songs/${song.toLowerCase()}/Inst$suffix.${extension}';
160163
}
161164

162165
public static function image(key:String, ?library:String):String

source/funkin/audio/FunkinSound.hx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,16 @@ class FunkinSound extends FlxSound implements ICloneable<FunkinSound>
5757
* Waveform data for this sound.
5858
* This is lazily loaded, so it will be built the first time it is accessed.
5959
*/
60-
public var waveformData(get, never):WaveformData;
60+
public var waveformData(get, never):Null<WaveformData>;
6161

6262
var _waveformData:Null<WaveformData> = null;
6363

64-
function get_waveformData():WaveformData
64+
function get_waveformData():Null<WaveformData>
6565
{
6666
if (_waveformData == null)
6767
{
6868
_waveformData = WaveformDataParser.interpretFlxSound(this);
69-
if (_waveformData == null) throw 'Could not interpret waveform data!';
69+
if (_waveformData == null) trace('Could not interpret waveform data!');
7070
}
7171
return _waveformData;
7272
}

source/funkin/audio/waveform/WaveformData.hx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ class WaveformData
195195
var thatChannel = that.channel(channelIndex);
196196
var resultChannel = result.channel(channelIndex);
197197

198+
if (thatChannel == null) return this.clone();
199+
198200
for (index in 0...this.length)
199201
{
200202
var thisMinSample = thisChannel.minSample(index);

source/funkin/data/song/importer/ChartManifestData.hx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package funkin.data.song.importer;
22

3+
import haxe.io.Path;
4+
35
/**
46
* A helper JSON blob found in `.fnfc` files.
57
*/
@@ -47,18 +49,32 @@ class ChartManifestData
4749
return '$songId-chart${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_DATA}';
4850
}
4951

50-
public function getInstFileName(?variation:String):String
52+
public function getInstFileName(?variation:String, fileEntries:Array<haxe.zip.Entry>):String
5153
{
5254
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
5355

54-
return 'Inst${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
56+
var instFile = fileEntries.filter(function(file:haxe.zip.Entry):Bool
57+
{
58+
return Path.withoutExtension(file.fileName) == 'Inst${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}';
59+
});
60+
61+
if (instFile[0] == null) return 'Inst${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
62+
else
63+
return instFile[0].fileName;
5564
}
5665

57-
public function getVocalsFileName(charId:String, ?variation:String):String
66+
public function getVocalsFileName(charId:String, ?variation:String, fileEntries:Array<haxe.zip.Entry>):String
5867
{
5968
if (variation == null || variation == '') variation = Constants.DEFAULT_VARIATION;
6069

61-
return 'Voices-$charId${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
70+
var vocalFile = fileEntries.filter(function(file:haxe.zip.Entry):Bool
71+
{
72+
return Path.withoutExtension(file.fileName) == 'Voices-$charId${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}';
73+
});
74+
75+
if (vocalFile[0] == null) return 'Voices-$charId${variation == Constants.DEFAULT_VARIATION ? '' : '-$variation'}.${Constants.EXT_SOUND}';
76+
else
77+
return vocalFile[0].fileName;
6278
}
6379

6480
/**

source/funkin/ui/debug/charting/ChartEditorState.hx

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,6 @@ class ChartEditorState extends UIState // UIState derives from MusicBeatState
148148
public static final CHART_EDITOR_TOOLBOX_FREEPLAY_LAYOUT:String = Paths.ui('chart-editor/toolbox/freeplay');
149149
public static final CHART_EDITOR_TOOLBOX_PLAYTEST_PROPERTIES_LAYOUT:String = Paths.ui('chart-editor/toolbox/playtest-properties');
150150

151-
// Validation
152-
public static final SUPPORTED_MUSIC_FORMATS:Array<String> = #if sys ['ogg'] #else ['mp3'] #end;
153-
154151
// Layout
155152

156153
/**

source/funkin/ui/debug/charting/dialogs/ChartEditorUploadVocalsDialog.hx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ class ChartEditorUploadVocalsDialog extends ChartEditorBaseDialog
109109

110110
vocalsEntry.onClick = function(_event)
111111
{
112-
Dialogs.openBinaryFile('Open $charName Vocals', [{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile)
112+
Dialogs.openBinaryFile('Open $charName Vocals', FileUtil.FILE_EXTENSION_INFO_AUDIO, function(selectedFile)
113113
{
114114
if (selectedFile != null && selectedFile.bytes != null)
115115
{

source/funkin/ui/debug/charting/handlers/ChartEditorAudioHandler.hx

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import funkin.audio.waveform.WaveformSprite;
1313
import flixel.util.FlxColor;
1414
import haxe.io.Bytes;
1515
import haxe.io.Path;
16+
import lime.media.AudioBuffer;
1617

1718
/**
1819
* Functions for loading audio for the chart editor.
@@ -69,6 +70,7 @@ class ChartEditorAudioHandler
6970
*/
7071
public static function loadVocalsFromBytes(state:ChartEditorState, bytes:Bytes, charId:String, instId:String = '', wipeFirst:Bool = false):Bool
7172
{
73+
if (AudioBuffer.getCodec(bytes) == null) return false;
7274
var trackId:String = '${charId}${instId == '' ? '' : '-${instId}'}';
7375
if (wipeFirst) wipeVocalData(state);
7476
state.audioVocalTrackData.set(trackId, bytes);
@@ -119,6 +121,7 @@ class ChartEditorAudioHandler
119121
*/
120122
public static function loadInstFromBytes(state:ChartEditorState, bytes:Bytes, instId:String = '', wipeFirst:Bool = false):Bool
121123
{
124+
if (AudioBuffer.getCodec(bytes) == null) return false;
122125
if (instId == '') instId = 'default';
123126
if (wipeFirst) wipeInstrumentalData(state);
124127
state.audioInstTrackData.set(instId, bytes);
@@ -339,26 +342,14 @@ class ChartEditorAudioHandler
339342
var instTrackIds = state.audioInstTrackData.keys().array();
340343
for (key in instTrackIds)
341344
{
342-
if (key == 'default')
343-
{
344-
var data:Null<Bytes> = state.audioInstTrackData.get('default');
345-
if (data == null)
346-
{
347-
trace(' WARNING '.warning() + ' Failed to access inst track ($key)');
348-
continue;
349-
}
350-
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Inst.ogg', data));
351-
}
352-
else
345+
var data:Null<Bytes> = state.audioInstTrackData.get(key);
346+
if (data == null)
353347
{
354-
var data:Null<Bytes> = state.audioInstTrackData.get(key);
355-
if (data == null)
356-
{
357-
trace(' WARNING '.warning() + ' Failed to access inst track ($key)');
358-
continue;
359-
}
360-
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Inst-${key}.ogg', data));
348+
trace(' WARNING '.warning() + ' Failed to access inst track ($key)');
349+
continue;
361350
}
351+
var extension = AudioBuffer.getCodec(data).toFormat();
352+
zipEntries.push(FileUtil.makeZIPEntryFromBytes(key == 'default' ? 'Inst.${extension}' : 'Inst-${key}.${extension}', data));
362353
}
363354

364355
return zipEntries;
@@ -382,7 +373,8 @@ class ChartEditorAudioHandler
382373
trace(' WARNING '.warning() + ' Failed to access vocal track ($key)');
383374
continue;
384375
}
385-
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Voices-${key}.ogg', data));
376+
var extension = AudioBuffer.getCodec(data).toFormat();
377+
zipEntries.push(FileUtil.makeZIPEntryFromBytes('Voices-${key}.${extension}', data));
386378
}
387379

388380
return zipEntries;

source/funkin/ui/debug/charting/handlers/ChartEditorDialogHandler.hx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ class ChartEditorDialogHandler
532532

533533
instrumentalBox.onClick = function(_)
534534
{
535-
Dialogs.openBinaryFile('Open Instrumental', [{label: 'Audio File (.ogg)', extension: 'ogg'}], function(selectedFile:SelectedFileInfo)
535+
Dialogs.openBinaryFile('Open Instrumental', FileUtil.FILE_EXTENSION_INFO_AUDIO, function(selectedFile:SelectedFileInfo)
536536
{
537537
if (selectedFile != null && selectedFile.bytes != null)
538538
{
@@ -567,17 +567,8 @@ class ChartEditorDialogHandler
567567
}
568568
else
569569
{
570-
var message:String = if (!ChartEditorState.SUPPORTED_MUSIC_FORMATS.contains(path.ext ?? ''))
571-
{
572-
'File format (${path.ext}) not supported for instrumental track (${path.file}.${path.ext})';
573-
}
574-
else
575-
{
576-
'Failed to load instrumental track (${path.file}.${path.ext}) for variation (${state.selectedVariation})';
577-
}
578-
579570
// Tell the user the load was successful.
580-
state.error('Failed to Load Instrumental', message);
571+
state.error('Failed to Load Instrumental', 'Failed to load instrumental track (${path.file}.${path.ext}) for variation (${state.selectedVariation})');
581572
}
582573
};
583574

source/funkin/ui/debug/charting/handlers/ChartEditorImportExportHandler.hx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,16 +297,15 @@ class ChartEditorImportExportHandler
297297
if (variMetadata == null) continue;
298298

299299
var instId:String = variMetadata?.playData?.characters?.instrumental ?? '';
300-
301-
var instFileName:String = manifest.getInstFileName(instId);
300+
var instFileName:String = manifest.getInstFileName(instId, fileEntries);
302301
var instFileBytes:Bytes = mappedFileEntries.get(instFileName)?.data ?? throw 'Could not locate instrumental ($instFileName).';
303302
if (!ChartEditorAudioHandler.loadInstFromBytes(state, instFileBytes, instId)) throw 'Could not load instrumental ($instFileName).';
304303

305304
var playerCharId:String = variMetadata?.playData?.characters?.player ?? Constants.DEFAULT_CHARACTER;
306305
var playerVoiceList:Array<String> = variMetadata?.playData.characters?.playerVocals ?? [playerCharId];
307306
for (voice in playerVoiceList)
308307
{
309-
var playerVocalsFileName:String = manifest.getVocalsFileName(voice, variation);
308+
var playerVocalsFileName:String = manifest.getVocalsFileName(voice, variation, fileEntries);
310309
var playerVocalsFileBytes:Null<Bytes> = mappedFileEntries.get(playerVocalsFileName)?.data;
311310
if (playerVocalsFileBytes == null)
312311
{
@@ -324,7 +323,7 @@ class ChartEditorImportExportHandler
324323
var opponentVoiceList:Array<String> = variMetadata?.playData.characters?.opponentVocals ?? [opponentCharId];
325324
for (voice in opponentVoiceList)
326325
{
327-
var opponentVocalsFileName:String = manifest.getVocalsFileName(voice, variation);
326+
var opponentVocalsFileName:String = manifest.getVocalsFileName(voice, variation, fileEntries);
328327
var opponentVocalsFileBytes:Null<Bytes> = mappedFileEntries.get(opponentVocalsFileName)?.data;
329328
if (opponentVocalsFileBytes == null)
330329
{

source/funkin/ui/debug/charting/toolboxes/ChartEditorFreeplayToolbox.hx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
324324
for (index in 0...numberOfTicks)
325325
{
326326
var tickPos = chartEditorState.offsetTickBitmap.width / 2 * index;
327-
var tickTime = tickPos * (waveformScale / BASE_SCALE * waveformMagicFactor) / waveformMusic.waveform.waveformData.pointsPerSecond();
327+
var tickTime = tickPos * (waveformScale / BASE_SCALE * waveformMagicFactor) / waveformMusic.waveform.waveformData?.pointsPerSecond();
328328

329329
var tickLabel:Label = new Label();
330330
tickLabel.text = formatTime(tickTime);
@@ -397,7 +397,7 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
397397

398398
// Move the audio preview to the playhead position.
399399
var currentWaveformIndex:Int = Std.int(playheadAbsolutePos * (waveformScale / BASE_SCALE * waveformMagicFactor));
400-
var targetSongTimeSeconds:Float = waveformMusic.waveform.waveformData.indexToSeconds(currentWaveformIndex);
400+
var targetSongTimeSeconds:Float = waveformMusic.waveform.waveformData?.indexToSeconds(currentWaveformIndex);
401401
audioPreviewTracks.time = targetSongTimeSeconds * Constants.MS_PER_SEC;
402402
}
403403

@@ -452,11 +452,11 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
452452

453453
var previewStartPosAbsolute = waveformDragPreviewStartPos + waveformScrollview.hscrollPos;
454454
var previewStartPosIndex:Int = Std.int(previewStartPosAbsolute * (waveformScale / BASE_SCALE * waveformMagicFactor));
455-
var previewStartPosMs:Int = Std.int(waveformMusic.waveform.waveformData.indexToSeconds(previewStartPosIndex) * Constants.MS_PER_SEC);
455+
var previewStartPosMs:Int = Std.int(waveformMusic.waveform.waveformData?.indexToSeconds(previewStartPosIndex) * Constants.MS_PER_SEC);
456456

457457
var previewEndPosAbsolute = waveformDragPreviewEndPos + waveformScrollview.hscrollPos;
458458
var previewEndPosIndex:Int = Std.int(previewEndPosAbsolute * (waveformScale / BASE_SCALE * waveformMagicFactor));
459-
var previewEndPosMs:Int = Std.int(waveformMusic.waveform.waveformData.indexToSeconds(previewEndPosIndex) * Constants.MS_PER_SEC);
459+
var previewEndPosMs:Int = Std.int(waveformMusic.waveform.waveformData?.indexToSeconds(previewEndPosIndex) * Constants.MS_PER_SEC);
460460

461461
chartEditorState.performCommand(new SetFreeplayPreviewCommand(previewStartPosMs, previewEndPosMs));
462462

@@ -629,7 +629,7 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
629629

630630
if (audioPreviewTracks.playing)
631631
{
632-
var targetScrollPos:Float = waveformMusic.waveform.waveformData.secondsToIndex(audioPreviewTracks.time / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
632+
var targetScrollPos:Float = waveformMusic.waveform.waveformData?.secondsToIndex(audioPreviewTracks.time / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
633633
// waveformScrollview.hscrollPos = targetScrollPos;
634634
var prevPlayheadAbsolutePos = playheadAbsolutePos;
635635
playheadAbsolutePos = targetScrollPos;
@@ -652,11 +652,11 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
652652
{
653653
var previewStartPosAbsolute = waveformDragPreviewStartPos + waveformScrollview.hscrollPos;
654654
var previewStartPosIndex:Int = Std.int(previewStartPosAbsolute * (waveformScale / BASE_SCALE * waveformMagicFactor));
655-
var previewStartPosMs:Int = Std.int(waveformMusic.waveform.waveformData.indexToSeconds(previewStartPosIndex) * Constants.MS_PER_SEC);
655+
var previewStartPosMs:Int = Std.int(waveformMusic.waveform.waveformData?.indexToSeconds(previewStartPosIndex) * Constants.MS_PER_SEC);
656656

657657
var previewEndPosAbsolute = waveformDragPreviewEndPos + waveformScrollview.hscrollPos;
658658
var previewEndPosIndex:Int = Std.int(previewEndPosAbsolute * (waveformScale / BASE_SCALE * waveformMagicFactor));
659-
var previewEndPosMs:Int = Std.int(waveformMusic.waveform.waveformData.indexToSeconds(previewEndPosIndex) * Constants.MS_PER_SEC);
659+
var previewEndPosMs:Int = Std.int(waveformMusic.waveform.waveformData?.indexToSeconds(previewEndPosIndex) * Constants.MS_PER_SEC);
660660

661661
// Set the values in milliseconds.
662662
freeplayPreviewStart.value = previewStartPosMs;
@@ -667,8 +667,8 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
667667
}
668668
else
669669
{
670-
previewBoxStartPosAbsolute = waveformMusic.waveform.waveformData.secondsToIndex(chartEditorState.currentSongFreeplayPreviewStart / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
671-
previewBoxEndPosAbsolute = waveformMusic.waveform.waveformData.secondsToIndex(chartEditorState.currentSongFreeplayPreviewEnd / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
670+
previewBoxStartPosAbsolute = waveformMusic.waveform.waveformData?.secondsToIndex(chartEditorState.currentSongFreeplayPreviewStart / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
671+
previewBoxEndPosAbsolute = waveformMusic.waveform.waveformData?.secondsToIndex(chartEditorState.currentSongFreeplayPreviewEnd / Constants.MS_PER_SEC) / (waveformScale / BASE_SCALE * waveformMagicFactor);
672672

673673
freeplayPreviewStart.value = chartEditorState.currentSongFreeplayPreviewStart;
674674
freeplayPreviewEnd.value = chartEditorState.currentSongFreeplayPreviewEnd;
@@ -679,7 +679,7 @@ class ChartEditorFreeplayToolbox extends ChartEditorBaseToolbox
679679
{
680680
super.refresh();
681681

682-
waveformMagicFactor = MAGIC_SCALE_BASE_TIME / (chartEditorState.offsetTickBitmap.width / waveformMusic.waveform.waveformData.pointsPerSecond());
682+
waveformMagicFactor = MAGIC_SCALE_BASE_TIME / (chartEditorState.offsetTickBitmap.width / waveformMusic.waveform.waveformData?.pointsPerSecond());
683683

684684
var currentZoomFactor = waveformScale / BASE_SCALE * waveformMagicFactor;
685685

0 commit comments

Comments
 (0)