Skip to content

Commit e33c19e

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

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
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 & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,44 @@ 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+
for (i in 0...soundData.length)
80+
{
81+
soundData[i] = Std.int(bytes.getFloat(i * 4) * INT16_MAX);
82+
}
83+
minSampleValue = INT16_MIN;
84+
maxSampleValue = INT16_MAX;
85+
default:
86+
throw 'Unsupported bits per sample: $bitsPerSample';
87+
}
5588

5689
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));
90+
var soundDataSampleCount:Int = Math.ceil(soundDataRawLength / channels);
91+
var outputPointCount:Int = Math.ceil(soundDataSampleCount / samplesPerPoint);
5992

6093
// trace('Interpreting audio buffer:');
6194
// trace(' sampleRate: ${sampleRate}');
@@ -68,9 +101,6 @@ class WaveformDataParser
68101
// trace(' soundDataRawLength/4: ${soundDataRawLength / 4}');
69102
// trace(' outputPointCount: ${outputPointCount}');
70103

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

76106
var perfStart:Float = TimerUtil.start();
@@ -82,8 +112,8 @@ class WaveformDataParser
82112

83113
for (i in 0...channels)
84114
{
85-
values.push(bitsPerSample == 16 ? INT16_MAX : INT8_MAX);
86-
values.push(bitsPerSample == 16 ? INT16_MIN : INT8_MIN);
115+
values.push(maxSampleValue);
116+
values.push(minSampleValue);
87117
}
88118

89119
var rangeStart = pointIndex * samplesPerPoint;
@@ -95,18 +125,20 @@ class WaveformDataParser
95125
for (channelIndex in 0...channels)
96126
{
97127
var sampleIndex:Int = sampleIndex * channels + channelIndex;
98-
var sampleValue = soundData[sampleIndex];
128+
var sampleValue:Int = soundData[sampleIndex];
99129

100130
if (sampleValue < values[channelIndex * 2]) values[(channelIndex * 2)] = sampleValue;
101131
if (sampleValue > values[channelIndex * 2 + 1]) values[(channelIndex * 2) + 1] = sampleValue;
102132
}
103133
}
104134

105135
// We now have the min and max values for the range.
106-
for (value in values)
107-
outputData.push(value);
136+
outputData = outputData.concat(values);
108137
}
109138

139+
// We cheated before by scaling the values to fit in a 16-bit range.
140+
if (bitsPerSample == 32) bitsPerSample = 16;
141+
110142
var outputDataLength:Int = Std.int(outputData.length / channels / 2);
111143
var result = new WaveformData(null, channels, sampleRate, samplesPerPoint, bitsPerSample, outputPointCount, outputData);
112144

0 commit comments

Comments
 (0)