Skip to content

Commit 93d7118

Browse files
committed
WaveformDataParser: 32bit float audio support
1 parent 1dba74c commit 93d7118

File tree

2 files changed

+47
-15
lines changed

2 files changed

+47
-15
lines changed

source/funkin/audio/waveform/WaveformData.hx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,12 @@ class WaveformData
7272
return (channelData == null) ? buildChannelData()[index] : channelData[index];
7373
}
7474

75-
public function get(index:Int):Int
75+
public inline function get(index:Int):Int
7676
{
7777
return data[index] ?? 0;
7878
}
7979

80-
public function set(index:Int, value:Int)
80+
public inline function set(index:Int, value:Int)
8181
{
8282
data[index] = value;
8383
}
@@ -88,8 +88,9 @@ class WaveformData
8888
*/
8989
public function maxSampleValue():Int
9090
{
91+
// TODO: Should this still be cached?
9192
if (_maxSampleValue != 0) return _maxSampleValue;
92-
return _maxSampleValue = Std.int(Math.pow(2, bits));
93+
return _maxSampleValue = 1 << bits;
9394
}
9495

9596
/**

source/funkin/audio/waveform/WaveformDataParser.hx

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,46 @@ class WaveformDataParser
5151
var pointsPerSecond:Float = sampleRate / samplesPerPoint; // 172 samples per second for most songs is plenty precise while still being performant..
5252

5353
// TODO: Make this work better on HTML5.
54-
var soundData:lime.utils.Int16Array = cast soundBuffer.data;
54+
var bytes:haxe.io.Bytes = soundBuffer.data.toBytes();
55+
var soundData:Array<Int> = [];
56+
soundData.resize(Std.int(bytes.length / (bitsPerSample / 8)));
57+
var minSampleValue:Int;
58+
var maxSampleValue:Int;
59+
60+
switch (bitsPerSample)
61+
{
62+
case 8:
63+
for (i in 0...soundData.length)
64+
{
65+
soundData[i] = bytes.get(i) - 128;
66+
}
67+
minSampleValue = INT8_MIN;
68+
maxSampleValue = INT8_MAX;
69+
case 16:
70+
for (i in 0...soundData.length)
71+
{
72+
var val = bytes.getUInt16(i * 2);
73+
if (val > INT16_MAX) val -= 65536;
74+
soundData[i] = val;
75+
};
76+
minSampleValue = INT16_MIN;
77+
maxSampleValue = INT16_MAX;
78+
case 32:
79+
// We cheat by scaling the values to fit in a 16-bit range.
80+
for (i in 0...soundData.length)
81+
{
82+
soundData[i] = Std.int(bytes.getFloat(i * 4) * INT16_MAX);
83+
}
84+
minSampleValue = INT16_MIN;
85+
maxSampleValue = INT16_MAX;
86+
bitsPerSample = 16;
87+
default:
88+
throw 'Unsupported bits per sample: $bitsPerSample';
89+
}
5590

5691
var soundDataRawLength:Int = soundData.length;
57-
var soundDataSampleCount:Int = Std.int(Math.ceil(soundDataRawLength / channels / (bitsPerSample == 16 ? 2 : 1)));
58-
var outputPointCount:Int = Std.int(Math.ceil(soundDataSampleCount / samplesPerPoint));
92+
var soundDataSampleCount:Int = Math.ceil(soundDataRawLength / channels / (bitsPerSample / 8));
93+
var outputPointCount:Int = Math.ceil(soundDataSampleCount / samplesPerPoint);
5994

6095
// trace('Interpreting audio buffer:');
6196
// trace(' sampleRate: ${sampleRate}');
@@ -68,9 +103,6 @@ class WaveformDataParser
68103
// trace(' soundDataRawLength/4: ${soundDataRawLength / 4}');
69104
// trace(' outputPointCount: ${outputPointCount}');
70105

71-
var minSampleValue:Int = bitsPerSample == 16 ? INT16_MIN : INT8_MIN;
72-
var maxSampleValue:Int = bitsPerSample == 16 ? INT16_MAX : INT8_MAX;
73-
74106
var outputData:Array<Int> = [];
75107

76108
var perfStart:Float = TimerUtil.start();
@@ -80,10 +112,10 @@ class WaveformDataParser
80112
// minChannel1, maxChannel1, minChannel2, maxChannel2, ...
81113
var values:Array<Int> = [];
82114

83-
for (i in 0...channels)
115+
for (_ in 0...channels)
84116
{
85-
values.push(bitsPerSample == 16 ? INT16_MAX : INT8_MAX);
86-
values.push(bitsPerSample == 16 ? INT16_MIN : INT8_MIN);
117+
values.push(maxSampleValue);
118+
values.push(minSampleValue);
87119
}
88120

89121
var rangeStart = pointIndex * samplesPerPoint;
@@ -95,16 +127,15 @@ class WaveformDataParser
95127
for (channelIndex in 0...channels)
96128
{
97129
var sampleIndex:Int = sampleIndex * channels + channelIndex;
98-
var sampleValue = soundData[sampleIndex];
130+
var sampleValue:Int = soundData[sampleIndex];
99131

100132
if (sampleValue < values[channelIndex * 2]) values[(channelIndex * 2)] = sampleValue;
101133
if (sampleValue > values[channelIndex * 2 + 1]) values[(channelIndex * 2) + 1] = sampleValue;
102134
}
103135
}
104136

105137
// We now have the min and max values for the range.
106-
for (value in values)
107-
outputData.push(value);
138+
outputData = outputData.concat(values);
108139
}
109140

110141
var outputDataLength:Int = Std.int(outputData.length / channels / 2);

0 commit comments

Comments
 (0)