react-native-tiny-wavpack-decoder 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +148 -0
  3. package/android/build.gradle +112 -0
  4. package/android/generated/java/com/tinywavpackdecoder/NativeTinyWavPackDecoderSpec.java +47 -0
  5. package/android/generated/jni/CMakeLists.txt +36 -0
  6. package/android/generated/jni/RNTinyWavPackDecoderSpec-generated.cpp +44 -0
  7. package/android/generated/jni/RNTinyWavPackDecoderSpec.h +31 -0
  8. package/android/generated/jni/react/renderer/components/RNTinyWavPackDecoderSpec/RNTinyWavPackDecoderSpecJSI-generated.cpp +46 -0
  9. package/android/generated/jni/react/renderer/components/RNTinyWavPackDecoderSpec/RNTinyWavPackDecoderSpecJSI.h +89 -0
  10. package/android/gradle.properties +5 -0
  11. package/android/src/main/AndroidManifest.xml +3 -0
  12. package/android/src/main/AndroidManifestNew.xml +2 -0
  13. package/android/src/main/cpp/CMakeLists.txt +54 -0
  14. package/android/src/main/cpp/TinyWavPackDecoderModule.cpp +118 -0
  15. package/android/src/main/java/com/tinywavpackdecoder/TinyWavPackDecoderModule.kt +114 -0
  16. package/android/src/main/java/com/tinywavpackdecoder/TinyWavPackDecoderPackage.kt +18 -0
  17. package/ios/TinyWavPackDecoder.h +8 -0
  18. package/ios/TinyWavPackDecoder.mm +83 -0
  19. package/ios/generated/RNTinyWavPackDecoderSpec/RNTinyWavPackDecoderSpec-generated.mm +53 -0
  20. package/ios/generated/RNTinyWavPackDecoderSpec/RNTinyWavPackDecoderSpec.h +69 -0
  21. package/ios/generated/RNTinyWavPackDecoderSpecJSI-generated.cpp +46 -0
  22. package/ios/generated/RNTinyWavPackDecoderSpecJSI.h +89 -0
  23. package/lib/module/NativeTinyWavPackDecoder.ts +19 -0
  24. package/lib/module/index.js +38 -0
  25. package/lib/module/index.js.map +1 -0
  26. package/lib/module/package.json +1 -0
  27. package/lib/module/tiny-wavpack/common/TinyWavPackDecoderInterface.c +414 -0
  28. package/lib/module/tiny-wavpack/common/TinyWavPackDecoderInterface.h +52 -0
  29. package/lib/module/tiny-wavpack/common/test.c +45 -0
  30. package/lib/module/tiny-wavpack/common/wv2wav +0 -0
  31. package/lib/module/tiny-wavpack/lib/bits.c +140 -0
  32. package/lib/module/tiny-wavpack/lib/float.c +50 -0
  33. package/lib/module/tiny-wavpack/lib/license.txt +25 -0
  34. package/lib/module/tiny-wavpack/lib/metadata.c +105 -0
  35. package/lib/module/tiny-wavpack/lib/readme.txt +68 -0
  36. package/lib/module/tiny-wavpack/lib/unpack.c +785 -0
  37. package/lib/module/tiny-wavpack/lib/wavpack.h +384 -0
  38. package/lib/module/tiny-wavpack/lib/words.c +560 -0
  39. package/lib/module/tiny-wavpack/lib/wputils.c +351 -0
  40. package/lib/typescript/package.json +1 -0
  41. package/lib/typescript/src/NativeTinyWavPackDecoder.d.ts +9 -0
  42. package/lib/typescript/src/NativeTinyWavPackDecoder.d.ts.map +1 -0
  43. package/lib/typescript/src/index.d.ts +18 -0
  44. package/lib/typescript/src/index.d.ts.map +1 -0
  45. package/package.json +195 -0
  46. package/react-native-wavpack-decoder.podspec +35 -0
  47. package/react-native.config.js +12 -0
  48. package/src/NativeTinyWavPackDecoder.ts +19 -0
  49. package/src/index.tsx +57 -0
  50. package/src/tiny-wavpack/common/TinyWavPackDecoderInterface.c +414 -0
  51. package/src/tiny-wavpack/common/TinyWavPackDecoderInterface.h +52 -0
  52. package/src/tiny-wavpack/common/test.c +45 -0
  53. package/src/tiny-wavpack/common/wv2wav +0 -0
  54. package/src/tiny-wavpack/lib/bits.c +140 -0
  55. package/src/tiny-wavpack/lib/float.c +50 -0
  56. package/src/tiny-wavpack/lib/license.txt +25 -0
  57. package/src/tiny-wavpack/lib/metadata.c +105 -0
  58. package/src/tiny-wavpack/lib/readme.txt +68 -0
  59. package/src/tiny-wavpack/lib/unpack.c +785 -0
  60. package/src/tiny-wavpack/lib/wavpack.h +384 -0
  61. package/src/tiny-wavpack/lib/words.c +560 -0
  62. package/src/tiny-wavpack/lib/wputils.c +351 -0
package/src/index.tsx ADDED
@@ -0,0 +1,57 @@
1
+ import NativeTinyWavPackDecoder from './NativeTinyWavPackDecoder';
2
+ import {
3
+ NativeModules,
4
+ NativeEventEmitter,
5
+ type EmitterSubscription,
6
+ } from 'react-native';
7
+
8
+ export interface TinyWavPackDecoderOptions {
9
+ maxSamples?: number;
10
+ bitsPerSample?: 8 | 16 | 24 | 32;
11
+ }
12
+
13
+ const { TinyWavPackDecoderModule } = NativeModules;
14
+ const emitter = new NativeEventEmitter(TinyWavPackDecoderModule);
15
+
16
+ const TinyWavPackDecoder = {
17
+ decode: async (
18
+ inputPath: string,
19
+ outputPath: string,
20
+ options: TinyWavPackDecoderOptions = {}
21
+ ): Promise<string> => {
22
+ const { maxSamples = -1, bitsPerSample = 16 } = options;
23
+
24
+ if (![8, 16, 24, 32].includes(bitsPerSample)) {
25
+ throw new Error('bitsPerSample must be 8, 16, 24, or 32');
26
+ }
27
+
28
+ return NativeTinyWavPackDecoder.decodeWavPack(
29
+ inputPath,
30
+ outputPath,
31
+ maxSamples,
32
+ bitsPerSample
33
+ );
34
+ },
35
+
36
+ /**
37
+ * Subscribe to native progress updates
38
+ */
39
+ addProgressListener: (
40
+ callback: (progress: number) => void
41
+ ): EmitterSubscription => {
42
+ return emitter.addListener('onProgressUpdate', (event) => {
43
+ if (typeof event?.progress === 'number') {
44
+ callback(event.progress);
45
+ }
46
+ });
47
+ },
48
+
49
+ /**
50
+ * Remove all native listeners for progress updates
51
+ */
52
+ removeAllListeners: (): void => {
53
+ emitter.removeAllListeners('onProgressUpdate');
54
+ },
55
+ };
56
+
57
+ export default TinyWavPackDecoder;
@@ -0,0 +1,414 @@
1
+ #include "TinyWavPackDecoderInterface.h"
2
+ #include "wavpack.h"
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <string.h>
6
+
7
+ // Static file pointer for wavpack read_bytes callback
8
+ static FILE *currentWvFile = NULL;
9
+
10
+ // WavPack callback for reading bytes from file
11
+ static int read_bytes(void *data, int bcount)
12
+ {
13
+ return (int)fread(data, 1, bcount, currentWvFile);
14
+ }
15
+
16
+ // Define error codes
17
+ #define ERR_FILE_OPEN_FAILED 1
18
+ #define ERR_WAVPACK_OPEN_FAILED 2
19
+ #define ERR_MEMORY_ALLOCATION_FAILED 3
20
+ #define ERR_INVALID_CHANNELS 4
21
+ #define ERR_INVALID_SAMPLES 5
22
+ #define ERR_DATA_OVERFLOW 6
23
+ #define ERR_WRITE_FAILED 7
24
+ #define ERR_DECODE_FAILED 8
25
+ #define ERR_INVALID_BPS 9
26
+
27
+ // Helper function to create and return an error result
28
+ static DecoderResult make_error(int code, const char *message)
29
+ {
30
+ DecoderResult result;
31
+ result.success = 0;
32
+ strncpy(result.error, message, sizeof(result.error) - 1);
33
+ result.error[sizeof(result.error) - 1] = '\0';
34
+ return result;
35
+ }
36
+
37
+ // Helper function to create and return a success result
38
+ static DecoderResult make_success()
39
+ {
40
+ DecoderResult result;
41
+ result.success = 1;
42
+ result.error[0] = '\0';
43
+ return result;
44
+ }
45
+
46
+ // Helper function to format samples to the desired bits per sample
47
+ static void format_samples(int bps, void *dst, int32_t *src, uint32_t samcnt, int is_float, int bitsPerSample)
48
+ {
49
+ switch (bps)
50
+ {
51
+ case 1:
52
+ { // 8-bit
53
+ uint8_t *d = (uint8_t *)dst;
54
+ for (uint32_t i = 0; i < samcnt; i++)
55
+ {
56
+ if (is_float)
57
+ {
58
+ float val = *(float *)(&src[i]);
59
+ val = val > 1.0f ? 1.0f : (val < -1.0f ? -1.0f : val);
60
+ d[i] = (uint8_t)((val * 127.0f) + 128);
61
+ }
62
+ else
63
+ {
64
+ int32_t val = src[i];
65
+ val = val > 32767 ? 32767 : (val < -32768 ? -32768 : val);
66
+ d[i] = (uint8_t)((val >> (bitsPerSample <= 16 ? 0 : (bitsPerSample - 16))) + 128);
67
+ }
68
+ }
69
+ break;
70
+ }
71
+ case 2:
72
+ { // 16-bit
73
+ int16_t *d = (int16_t *)dst;
74
+ for (uint32_t i = 0; i < samcnt; i++)
75
+ {
76
+ if (is_float)
77
+ {
78
+ float val = *(float *)(&src[i]);
79
+ val = val > 1.0f ? 1.0f : (val < -1.0f ? -1.0f : val);
80
+ d[i] = (int16_t)(val * 32767.0f);
81
+ }
82
+ else
83
+ {
84
+ int32_t val = src[i];
85
+ val = val > 32767 ? 32767 : (val < -32768 ? -32768 : val);
86
+ d[i] = (int16_t)(bitsPerSample <= 16 ? val : (val >> (bitsPerSample - 16)));
87
+ }
88
+ }
89
+ break;
90
+ }
91
+ case 3:
92
+ { // 24-bit
93
+ uint8_t *d = (uint8_t *)dst;
94
+ for (uint32_t i = 0; i < samcnt; i++)
95
+ {
96
+ int32_t val;
97
+ if (is_float)
98
+ {
99
+ float fval = *(float *)(&src[i]);
100
+ fval = fval > 1.0f ? 1.0f : (fval < -1.0f ? -1.0f : fval);
101
+ val = (int32_t)(fval * 8388607.0f);
102
+ }
103
+ else
104
+ {
105
+ val = src[i];
106
+ val = val > 8388607 ? 8388607 : (val < -8388608 ? -8388608 : val);
107
+ }
108
+ d[i * 3] = (uint8_t)(val);
109
+ d[i * 3 + 1] = (uint8_t)(val >> 8);
110
+ d[i * 3 + 2] = (uint8_t)(val >> 16);
111
+ }
112
+ break;
113
+ }
114
+ case 4:
115
+ { // 32-bit
116
+ int32_t *d = (int32_t *)dst;
117
+ for (uint32_t i = 0; i < samcnt; i++)
118
+ {
119
+ if (is_float)
120
+ {
121
+ float val = *(float *)(&src[i]);
122
+ val = val > 1.0f ? 1.0f : (val < -1.0f ? -1.0f : val);
123
+ d[i] = (int32_t)(val * 2147483647.0f);
124
+ }
125
+ else
126
+ {
127
+ d[i] = src[i];
128
+ }
129
+ }
130
+ break;
131
+ }
132
+ }
133
+ }
134
+
135
+ DecoderResult decode_wavpack_to_wav(
136
+ const char *inputPath,
137
+ const char *outputPath,
138
+ int max_samples,
139
+ int force_bps,
140
+ ProgressCallback progress_callback,
141
+ void *context)
142
+ {
143
+ // Validate inputs
144
+ if (!inputPath || !outputPath)
145
+ {
146
+ return make_error(ERR_FILE_OPEN_FAILED, "Invalid input or output path");
147
+ }
148
+ if (max_samples < -1)
149
+ {
150
+ return make_error(ERR_INVALID_SAMPLES, "Invalid max samples");
151
+ }
152
+ if (force_bps && force_bps != 8 && force_bps != 16 && force_bps != 24 && force_bps != 32)
153
+ {
154
+ return make_error(ERR_INVALID_BPS, "Invalid bits per sample (must be 8, 16, 24, or 32)");
155
+ }
156
+
157
+ // Buffer for WavPack error messages
158
+ char error[80];
159
+
160
+ // Local variable to ensure each method call has its own isolated file handle.
161
+ FILE *wvFile = NULL;
162
+ FILE *wavFile = NULL;
163
+
164
+ // Opens the .wv file in binary read mode ("rb").
165
+ wvFile = fopen(inputPath, "rb");
166
+
167
+ /* If it fails (e.g., file doesn’t exist), rejects the promise with an error
168
+ message and exits. */
169
+ if (!wvFile)
170
+ {
171
+ return make_error(ERR_FILE_OPEN_FAILED, "Cannot open input file");
172
+ }
173
+
174
+ // Set static file pointer for read_bytes callback
175
+ currentWvFile = wvFile;
176
+
177
+ /* Creates a WavPack context using the read_bytes callback. If it fails (e.g.,
178
+ invalid WavPack file), rejects with the error message from error and closes
179
+ the file. */
180
+ WavpackContext *wpc = WavpackOpenFileInput(read_bytes, error);
181
+ if (!wpc)
182
+ {
183
+ fclose(wvFile);
184
+ currentWvFile = NULL;
185
+ return make_error(ERR_WAVPACK_OPEN_FAILED, error);
186
+ }
187
+
188
+ //////////////// Extracts audio properties from the WavPack file ///////////////
189
+ int numChannels = WavpackGetNumChannels(wpc); // Number of channels (e.g., 1 or 2).
190
+ int sampleRate = WavpackGetSampleRate(wpc); // Samples per second (e.g., 44100 Hz).
191
+ int bitsPerSample = WavpackGetBitsPerSample(wpc); // Original bit depth (e.g., 16, 24).
192
+ int numSamples = WavpackGetNumSamples(wpc); // Total number of samples.
193
+ int flags = WavpackGetMode(wpc); // Check for float format
194
+ int isFloatFormat = (flags & MODE_FLOAT) != 0;
195
+ ////////////////////////////////////////////////////////////////////////////////
196
+
197
+ //////////// Sanity check for buffer size before memory allocation /////////////
198
+ // Validate channel count
199
+ if (numChannels <= 0 || numChannels > 100)
200
+ {
201
+ fclose(wvFile);
202
+ currentWvFile = NULL;
203
+ return make_error(ERR_INVALID_CHANNELS, "Invalid number of channels");
204
+ }
205
+
206
+ // Validate sample count
207
+ if (numSamples <= 0)
208
+ {
209
+ fclose(wvFile);
210
+ currentWvFile = NULL;
211
+ return make_error(ERR_INVALID_SAMPLES, "Invalid number of samples");
212
+ }
213
+
214
+ // Calculate samples to decode
215
+ uint32_t samples_to_decode = (max_samples == -1) ? numSamples : (max_samples > numSamples ? numSamples : max_samples);
216
+
217
+ // Opens the .wav file in binary write mode ("wb")
218
+ wavFile = fopen(outputPath, "wb");
219
+ if (!wavFile)
220
+ {
221
+ // If it fails (e.g., permissions issue), make error and close the input file.
222
+ fclose(wvFile);
223
+ currentWvFile = NULL;
224
+ return make_error(ERR_FILE_OPEN_FAILED, "Cannot open output file");
225
+ }
226
+ ////////////////////////////////////////////////////////////////////////////////
227
+
228
+ /////////////////////////////// Write WAV Header ///////////////////////////////
229
+ uint32_t bytesPerSample = force_bps ? (force_bps / 8) : 2; // Default to 16-bit if not forced
230
+
231
+ // Avoid overflow: Checks if the total size of audio data exceeds 32-bit limit.
232
+ if ((uint64_t)samples_to_decode * numChannels * bytesPerSample > UINT32_MAX)
233
+ {
234
+ fclose(wavFile);
235
+ fclose(wvFile);
236
+ currentWvFile = NULL;
237
+ return make_error(ERR_DATA_OVERFLOW, "Audio data size exceeds 32-bit limit");
238
+ }
239
+
240
+ uint32_t dataSize = samples_to_decode * numChannels * bytesPerSample; // Total audio data size in bytes.
241
+
242
+ // Create and write WAV header
243
+ WavHeader header = {
244
+ /* "RIFF" identifier: Marks the start of a RIFF file. Every WAV file begins
245
+ with this */
246
+ .riff = {'R', 'I', 'F', 'F'}, // "RIFF"
247
+
248
+ /* A 32-bit unsigned integer representing the total file size minus 8 bytes
249
+ (the size of riff and fileSize fields). */
250
+ .fileSize = dataSize + 36,
251
+
252
+ /* The RIFF format identifier, a 4-byte string: Specifies that this RIFF
253
+ file is a WAV audio file. */
254
+ .wave = {'W', 'A', 'V', 'E'}, // "WAVE"
255
+
256
+ /* The format chunk identifier, a 4-byte string: Marks the start of the format
257
+ chunk, which describes the audio properties. The space is part of the standard. */
258
+ .fmt = {'f', 'm', 't', ' '}, // "fmt "
259
+
260
+ /* A 32-bit unsigned integer indicating the size of the format chunk data
261
+ (excluding fmt and fmtSize): Specifies how many bytes follow in the fmt chunk.
262
+ 16 bytes (for PCM, this is fixed: audioFormat [2] + numChannels [2] + sampleRate [4] + byteRate [4] + blockAlign [2] + bitsPerSample [2]). */
263
+ .fmtSize = 16, // 16 for PCM
264
+
265
+ /* A 16-bit unsigned integer specifying the audio format: 1 (means uncompressed
266
+ PCM). This tells the player the data is raw PCM, not compressed (e.g., MP3
267
+ would be a different value). */
268
+ .audioFormat = 1,
269
+
270
+ /* A 16-bit unsigned integer for the number of audio channels. Cast from int
271
+ numChannels (from WavpackGetNumChannels), typically 1 (mono) or 2 (stereo). */
272
+ .numChannels = (uint16_t)numChannels,
273
+
274
+ /* A 32-bit unsigned integer for the sample rate in Hz. Cast from int sampleRate
275
+ (from WavpackGetSampleRate), e.g., 44100 Hz. Defines how many samples per
276
+ second the audio contains.*/
277
+ .sampleRate = (uint32_t)sampleRate,
278
+
279
+ /* A 32-bit unsigned integer for the average bytes per second.
280
+ sampleRate * numChannels * bytesPerSample (e.g., 44100 * 2 * 2 = 176400 bytes/sec for stereo 16-bit at 44.1 kHz).
281
+ bytesPerSample is fixed at 2 (16 bits / 8 = 2 bytes). Helps players determine
282
+ playback speed and buffer requirements.*/
283
+ .byteRate = (uint32_t)(sampleRate * numChannels * bytesPerSample),
284
+
285
+ /* A 16-bit unsigned integer for the byte size of one sample frame.
286
+ numChannels * bytesPerSample (e.g., 2 * 2 = 4 bytes for stereo 16-bit).
287
+ Specifies the alignment of sample data (how many bytes per multi-channel sample).*/
288
+ .blockAlign = (uint16_t)(numChannels * bytesPerSample),
289
+
290
+ /* A 16-bit unsigned integer for the bits per sample. Defines the resolution
291
+ of each sample (8-bit, 16-bit, 24-bit, or 32-bit).*/
292
+ .bitsPerSample = (uint16_t)(bytesPerSample * 8),
293
+
294
+ /* The data chunk identifier, a 4-byte string. Marks the start of the audio
295
+ data chunk.*/
296
+ .data = {'d', 'a', 't', 'a'},
297
+
298
+ /* A 32-bit unsigned integer for the size of the audio data in bytes.
299
+ dataSize (from numSamples * numChannels * bytesPerSample).
300
+ Tells the player how many bytes of raw audio data follow. */
301
+ .dataSize = dataSize};
302
+
303
+ // This ensures the header is written successfully before proceeding to decode and write audio data.
304
+ if (fwrite(&header, sizeof(WavHeader), 1, wavFile) != 1)
305
+ {
306
+ fclose(wavFile);
307
+ fclose(wvFile);
308
+ currentWvFile = NULL;
309
+ return make_error(ERR_WRITE_FAILED, "Failed to write WAV header");
310
+ }
311
+ ////////////////////////////////////////////////////////////////////////////////
312
+
313
+ // Allocate buffers for decoding
314
+ const int BUFFER_SIZE = 4096;
315
+
316
+ // For 32-bit samples from WavPack.
317
+ int32_t *buffer = (int32_t *)malloc(BUFFER_SIZE * numChannels * sizeof(int32_t));
318
+
319
+ // For output samples (size depends on bits per sample).
320
+ void *samples = malloc(BUFFER_SIZE * numChannels * bytesPerSample);
321
+
322
+ // If allocation fails, rejects and cleans up.
323
+ if (!buffer || !samples)
324
+ {
325
+ if (buffer)
326
+ free(buffer);
327
+ if (samples)
328
+ free(samples);
329
+ fclose(wavFile);
330
+ fclose(wvFile);
331
+ currentWvFile = NULL;
332
+ return make_error(ERR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed");
333
+ }
334
+
335
+ ///////////////////////////////// Decoding Loop ////////////////////////////////
336
+ int totalSamplesRead = 0;
337
+
338
+ /* Loop:
339
+ - Calculates how many samples to read per iteration (up to BUFFER_SIZE).
340
+ - WavpackUnpackSamples: Fills buffer with decoded samples.
341
+ - Converts samples to the desired bit depth:
342
+ - Float: Scales [-1.0, 1.0] to appropriate range for output bits per sample.
343
+ - Integer: Direct cast or shifts as needed.
344
+ - Writes converted samples to the .wav file.
345
+ - Exits if no more samples are read (samplesRead <= 0). */
346
+ while (totalSamplesRead < samples_to_decode)
347
+ {
348
+ int samplesToRead = (samples_to_decode - totalSamplesRead < BUFFER_SIZE) ? samples_to_decode - totalSamplesRead : BUFFER_SIZE;
349
+
350
+ int samplesRead = WavpackUnpackSamples(wpc, buffer, samplesToRead);
351
+
352
+ if (samplesRead < 0)
353
+ {
354
+ free(buffer);
355
+ free(samples);
356
+ fclose(wavFile);
357
+ fclose(wvFile);
358
+ currentWvFile = NULL;
359
+ return make_error(ERR_DECODE_FAILED, "Failed to unpack samples");
360
+ }
361
+
362
+ /* Handle Incomplete Decoding: Rejects on negative return (error), logs a
363
+ warning for partial reads, and continues cleanly on zero. */
364
+ if (samplesRead == 0)
365
+ break;
366
+
367
+ // Convert samples to desired bit depth
368
+ format_samples(bytesPerSample, samples, buffer, samplesRead * numChannels, isFloatFormat, bitsPerSample);
369
+
370
+ // This catches write failures (e.g., disk full) during the sample writing process, allowing cleanup and error reporting.
371
+ if (fwrite(samples, bytesPerSample, samplesRead * numChannels, wavFile) != samplesRead * numChannels)
372
+ {
373
+ free(buffer);
374
+ free(samples);
375
+ fclose(wavFile);
376
+ fclose(wvFile);
377
+ currentWvFile = NULL;
378
+ return make_error(ERR_WRITE_FAILED, "Failed to write audio samples");
379
+ }
380
+
381
+ totalSamplesRead += samplesRead;
382
+
383
+ if (progress_callback)
384
+ {
385
+ progress_callback((float)totalSamplesRead / samples_to_decode, context);
386
+ }
387
+ }
388
+ ////////////////////////////////////////////////////////////////////////////////
389
+
390
+ // Clean up: closes files & frees buffers.
391
+ free(buffer);
392
+ free(samples);
393
+ fclose(wavFile);
394
+ fclose(wvFile);
395
+ currentWvFile = NULL;
396
+
397
+ // Check for errors
398
+ if (WavpackGetNumErrors(wpc) > 0)
399
+ {
400
+ char err_msg[80];
401
+ snprintf(err_msg, sizeof(err_msg), "Decoding failed with %d CRC errors", WavpackGetNumErrors(wpc));
402
+ return make_error(ERR_DECODE_FAILED, err_msg);
403
+ }
404
+
405
+ // Check if all requested samples were decoded
406
+ if (totalSamplesRead == samples_to_decode)
407
+ {
408
+ return make_success();
409
+ }
410
+ else
411
+ {
412
+ return make_error(ERR_DECODE_FAILED, "Failed to decode all requested samples");
413
+ }
414
+ }
@@ -0,0 +1,52 @@
1
+ #ifndef TINY_WAVPACK_DECODER_INTERFACE_H
2
+ #define TINY_WAVPACK_DECODER_INTERFACE_H
3
+
4
+ #include <stdint.h>
5
+
6
+ #ifdef __cplusplus
7
+ extern "C"
8
+ {
9
+ #endif
10
+
11
+ // WAV header structure
12
+ typedef struct
13
+ {
14
+ char riff[4]; // "RIFF"
15
+ uint32_t fileSize; // File size - 8
16
+ char wave[4]; // "WAVE"
17
+ char fmt[4]; // "fmt "
18
+ uint32_t fmtSize; // 16 for PCM
19
+ uint16_t audioFormat; // 1 for PCM
20
+ uint16_t numChannels; // 1 or 2
21
+ uint32_t sampleRate; // e.g., 44100
22
+ uint32_t byteRate; // sampleRate * numChannels * bitsPerSample / 8
23
+ uint16_t blockAlign; // numChannels * bitsPerSample / 8
24
+ uint16_t bitsPerSample; // 8, 16, 24, or 32
25
+ char data[4]; // "data"
26
+ uint32_t dataSize; // Size of the data chunk
27
+ } WavHeader;
28
+
29
+ // Result struct to handle decoding results and errors
30
+ typedef struct
31
+ {
32
+ int success; // 1 for success, 0 for failure
33
+ char error[80]; // Error message if any
34
+ } DecoderResult;
35
+
36
+ // Callback function pointer type
37
+ typedef void (*ProgressCallback)(float progress, void *context);
38
+
39
+ // Core decoding function
40
+ DecoderResult decode_wavpack_to_wav(
41
+ const char *inputPath,
42
+ const char *outputPath,
43
+ int max_samples,
44
+ int force_bps,
45
+ ProgressCallback progress_callback,
46
+ void *context);
47
+
48
+ #ifdef __cplusplus
49
+ }
50
+ #endif
51
+
52
+ #endif // TINY_WAVPACK_DECODER_INTERFACE_H
@@ -0,0 +1,45 @@
1
+ // #include "TinyWavPackDecoderInterface.h"
2
+ // #include <stdio.h>
3
+ // #include <stdlib.h>
4
+ // #include <string.h>
5
+
6
+ // int main(int argc, char *argv[]) {
7
+ // if (argc < 3) {
8
+ // printf("Usage: %s <input.wv> <output.wav> [-m max_samples] [-b bits_per_sample] [-v]\n", argv[0]);
9
+ // printf(" -m: max samples to decode (-1 for all, default -1)\n");
10
+ // printf(" -b: bits per sample (8, 16, 24, 32, default 16)\n");
11
+ // printf(" -v: verbose output\n");
12
+ // return 1;
13
+ // }
14
+
15
+ // const char* inputPath = argv[1];
16
+ // const char* outputPath = argv[2];
17
+ // int max_samples = -1;
18
+ // int force_bps = 16; // Default to 16-bit
19
+ // int verbose = 0;
20
+
21
+ // for (int i = 3; i < argc; i++) {
22
+ // if (strcmp(argv[i], "-m") == 0 && i + 1 < argc) {
23
+ // max_samples = atoi(argv[++i]);
24
+ // }
25
+ // else if (strcmp(argv[i], "-b") == 0 && i + 1 < argc) {
26
+ // force_bps = atoi(argv[++i]);
27
+ // }
28
+ // else if (strcmp(argv[i], "-v") == 0) {
29
+ // verbose = 1;
30
+ // }
31
+ // else {
32
+ // printf("Unknown option: %s\n", argv[i]);
33
+ // return 1;
34
+ // }
35
+ // }
36
+
37
+ // DecoderResult result = decode_wavpack_to_wav(inputPath, outputPath, max_samples, force_bps, verbose);
38
+ // if (result.success) {
39
+ // printf("Decoding successful: %s created\n", outputPath);
40
+ // } else {
41
+ // printf("Decoding failed: %s\n", result.error);
42
+ // }
43
+
44
+ // return result.success ? 0 : 1;
45
+ // }
Binary file