1) Don't calculate big LUTs for mixer deltas on init (was just a waste of RAM) 2) The mixer now uses a 64-bit division to calculate max number of safe samples to mix (branchless), instead of using a big hackish LUT for DIV->MUL 3) Module and sample loaders have been refactored so that it's much simpler to write new loaders (or modify the old ones) 4) Added support for importing DIGI Booster (non-Pro) modules 5) Added support for importing 8-channel StarTrekker modules 6) Updated help text 7) Some more minor code change 8) Updated the Visual Studio project and make scripts to include the new loaders * Sorry for not making individual commits for all the changes, but at this point it was simply too difficult for me to do so!
Showing the changes to src/ft2_sample_loader.c (1 of 37 files). Show all
Unified · Split
| @@ -16,1885 +16,124 @@ · 15 unmodified lines | ||
| 16 | 16 | #include "ft2_diskop.h" |
| 17 | 17 | #include "ft2_structs.h" |
| 18 | 18 | |
| 19 | −/* All of these routines were written from scratch and were not present | |
| 20 | −** in original FT2. | |
| 21 | −*/ | |
| 19 | +bool loadAIFF(FILE *f, uint32_t filesize); | |
| 20 | +bool loadIFF(FILE *f, uint32_t filesize); | |
| 21 | +bool loadRAW(FILE *f, uint32_t filesize); | |
| 22 | +bool loadWAV(FILE *f, uint32_t filesize); | |
| 22 | 23 | |
| 23 | 24 | enum |
| 24 | 25 | { |
| 25 | − STEREO_SAMPLE_READ_LEFT = 1, | |
| 26 | − STEREO_SAMPLE_READ_RIGHT = 2, | |
| 27 | − STEREO_SAMPLE_CONVERT = 3, | |
| 28 | − | |
| 29 | − WAV_FORMAT_PCM = 0x0001, | |
| 30 | − WAV_FORMAT_IEEE_FLOAT = 0x0003 | |
| 31 | −}; | |
| 32 | − | |
| 33 | −static volatile bool sampleIsLoading; | |
| 34 | −static bool loadAsInstrFlag; | |
| 35 | −static uint8_t sampleSlot; | |
| 36 | −static int16_t stereoSampleLoadMode; | |
| 37 | −static SDL_Thread *thread; | |
| 38 | − | |
| 39 | −static void normalize32bitSigned(int32_t *sampleData, uint32_t sampleLength); | |
| 40 | −static void normalize16bitFloatSigned(float *fSampleData, uint32_t sampleLength); | |
| 41 | −static void normalize64bitDoubleSigned(double *dSampleData, uint32_t sampleLength); | |
| 42 | − | |
| 43 | −void freeTmpSample(sampleTyp *s) | |
| 44 | −{ | |
| 45 | − if (s->origPek != NULL) | |
| 46 | − { | |
| 47 | − free(s->origPek); | |
| 48 | − s->origPek = NULL; | |
| 49 | − s->pek = NULL; | |
| 50 | − } | |
| 51 | − | |
| 52 | − memset(s, 0, sizeof (sampleTyp)); | |
| 53 | −} | |
| 54 | − | |
| 55 | −void removeSampleIsLoadingFlag(void) | |
| 56 | −{ | |
| 57 | − sampleIsLoading = false; | |
| 58 | −} | |
| 59 | − | |
| 60 | −static int32_t getAIFFRate(uint8_t *in) | |
| 61 | −{ | |
| 62 | − int32_t exp = (int32_t)(((in[0] & 0x7F) << 8) | in[1]); | |
| 63 | − uint32_t lo = (in[2] << 24) | (in[3] << 16) | (in[4] << 8) | in[5]; | |
| 64 | − uint32_t hi = (in[6] << 24) | (in[7] << 16) | (in[8] << 8) | in[9]; | |
| 65 | − | |
| 66 | − if (exp == 0 && lo == 0 && hi == 0) | |
| 67 | − return 0; | |
| 68 | − | |
| 69 | − exp -= 16383; | |
| 70 | − | |
| 71 | − double dOut = ldexp(lo, -31 + exp) + ldexp(hi, -63 + exp); | |
| 72 | − return (int32_t)(dOut + 0.5); // rounded | |
| 73 | −} | |
| 74 | − | |
| 75 | −static bool aiffIsStereo(FILE *f) // only ran on files that are confirmed to be AIFFs | |
| 76 | −{ | |
| 77 | − uint16_t numChannels; | |
| 78 | − uint32_t chunkID, chunkSize; | |
| 79 | − | |
| 80 | − uint32_t oldPos = ftell(f); | |
| 81 | − | |
| 82 | − fseek(f, 0, SEEK_END); | |
| 83 | − int32_t filesize = ftell(f); | |
| 84 | − | |
| 85 | − if (filesize < 12) | |
| 86 | − { | |
| 87 | − fseek(f, oldPos, SEEK_SET); | |
| 88 | − return false; | |
| 89 | − } | |
| 90 | − | |
| 91 | − fseek(f, 12, SEEK_SET); | |
| 92 | − | |
| 93 | − uint32_t commPtr = 0; | |
| 94 | − uint32_t commLen = 0; | |
| 95 | − | |
| 96 | − int32_t bytesRead = 0; | |
| 97 | − while (!feof(f) && bytesRead < filesize-12) | |
| 98 | − { | |
| 99 | − fread(&chunkID, 4, 1, f); chunkID = SWAP32(chunkID); if (feof(f)) break; | |
| 100 | − fread(&chunkSize, 4, 1, f); chunkSize = SWAP32(chunkSize); if (feof(f)) break; | |
| 101 | − | |
| 102 | − int32_t endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1); | |
| 103 | − switch (chunkID) | |
| 104 | − { | |
| 105 | − case 0x434F4D4D: // "COMM" | |
| 106 | − { | |
| 107 | − commPtr = ftell(f); | |
| 108 | − commLen = chunkSize; | |
| 109 | − } | |
| 110 | − break; | |
| 111 | − | |
| 112 | − default: break; | |
| 113 | − } | |
| 114 | − | |
| 115 | − bytesRead += (chunkSize + (chunkSize & 1)); | |
| 116 | − fseek(f, endOfChunk, SEEK_SET); | |
| 117 | − } | |
| 118 | − | |
| 119 | − if (commPtr == 0 || commLen < 2) | |
| 120 | − { | |
| 121 | − fseek(f, oldPos, SEEK_SET); | |
| 122 | − return false; | |
| 123 | − } | |
| 124 | − | |
| 125 | − fseek(f, commPtr, SEEK_SET); | |
| 126 | − fread(&numChannels, 2, 1, f); numChannels = SWAP16(numChannels); | |
| 127 | − fseek(f, oldPos, SEEK_SET); | |
| 128 | − | |
| 129 | − return (numChannels == 2); | |
| 130 | −} | |
| 131 | − | |
| 132 | −static bool wavIsStereo(FILE *f) // only ran on files that are confirmed to be WAVs | |
| 133 | −{ | |
| 134 | − uint16_t numChannels; | |
| 135 | − uint32_t chunkID, chunkSize; | |
| 136 | − | |
| 137 | − uint32_t oldPos = ftell(f); | |
| 138 | − | |
| 139 | − fseek(f, 0, SEEK_END); | |
| 140 | − int32_t filesize = ftell(f); | |
| 141 | − | |
| 142 | − if (filesize < 12) | |
| 143 | − { | |
| 144 | − fseek(f, oldPos, SEEK_SET); | |
| 145 | − return false; | |
| 146 | − } | |
| 147 | − | |
| 148 | − fseek(f, 12, SEEK_SET); | |
| 149 | − | |
| 150 | − uint32_t fmtPtr = 0; | |
| 151 | − uint32_t fmtLen = 0; | |
| 152 | − | |
| 153 | − int32_t bytesRead = 0; | |
| 154 | − while (!feof(f) && bytesRead < filesize-12) | |
| 155 | − { | |
| 156 | − fread(&chunkID, 4, 1, f); if (feof(f)) break; | |
| 157 | − fread(&chunkSize, 4, 1, f); if (feof(f)) break; | |
| 158 | − | |
| 159 | − int32_t endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1); | |
| 160 | − switch (chunkID) | |
| 161 | − { | |
| 162 | − case 0x20746D66: // "fmt " | |
| 163 | − { | |
| 164 | − fmtPtr = ftell(f); | |
| 165 | − fmtLen = chunkSize; | |
| 166 | − } | |
| 167 | − break; | |
| 168 | − | |
| 169 | − default: break; | |
| 170 | − } | |
| 171 | − | |
| 172 | − bytesRead += (chunkSize + (chunkSize & 1)); | |
| 173 | − fseek(f, endOfChunk, SEEK_SET); | |
| 174 | − } | |
| 175 | − | |
| 176 | − if (fmtPtr == 0 || fmtLen < 4) | |
| 177 | − { | |
| 178 | − fseek(f, oldPos, SEEK_SET); | |
| 179 | − return false; | |
| 180 | − } | |
| 181 | − | |
| 182 | − fseek(f, fmtPtr + 2, SEEK_SET); | |
| 183 | − fread(&numChannels, 2, 1, f); | |
| 184 | − fseek(f, oldPos, SEEK_SET); | |
| 185 | − | |
| 186 | − return (numChannels == 2); | |
| 187 | −} | |
| 188 | − | |
| 189 | −static int32_t SDLCALL loadAIFFSample(void *ptr) | |
| 190 | −{ | |
| 191 | − char compType[4]; | |
| 192 | − int8_t *audioDataS8; | |
| 193 | − uint8_t sampleRateBytes[10], *audioDataU8; | |
| 194 | − int16_t *audioDataS16, *audioDataS16_2, smp16; | |
| 195 | − uint16_t numChannels, bitDepth; | |
| 196 | − int32_t j, smp32, *audioDataS32; | |
| 197 | − uint32_t i, blockName, blockSize; | |
| 198 | − uint32_t offset, len32; | |
| 199 | − int64_t smp64; | |
| 200 | − sampleTyp tmpSmp; | |
| 201 | − | |
| 202 | − // this is important for the "goto" on load error | |
| 203 | − FILE *f = NULL; | |
| 204 | − memset(&tmpSmp, 0, sizeof (tmpSmp)); | |
| 205 | − | |
| 206 | − if (editor.tmpFilenameU == NULL) | |
| 207 | − { | |
| 208 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 209 | − goto aiffLoadError; | |
| 210 | − } | |
| 211 | − | |
| 212 | − UNICHAR *filename = editor.tmpFilenameU; | |
| 213 | − | |
| 214 | − f = UNICHAR_FOPEN(filename, "rb"); | |
| 215 | − if (f == NULL) | |
| 216 | − { | |
| 217 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 218 | − goto aiffLoadError; | |
| 219 | − } | |
| 220 | − | |
| 221 | − fseek(f, 0, SEEK_END); | |
| 222 | − int32_t filesize = ftell(f); | |
| 223 | − if (filesize < 12) | |
| 224 | − { | |
| 225 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 226 | − goto aiffLoadError; | |
| 227 | − } | |
| 228 | − | |
| 229 | − // handle chunks | |
| 230 | − | |
| 231 | − uint32_t commPtr = 0; | |
| 232 | − uint32_t commLen = 0; | |
| 233 | − uint32_t ssndPtr = 0; | |
| 234 | − uint32_t ssndLen = 0; | |
| 235 | − | |
| 236 | − fseek(f, 12, SEEK_SET); | |
| 237 | − while (!feof(f) && ftell(f) < filesize-12) | |
| 238 | − { | |
| 239 | − fread(&blockName, 4, 1, f); if (feof(f)) break; | |
| 240 | − fread(&blockSize, 4, 1, f); if (feof(f)) break; | |
| 241 | − | |
| 242 | − blockName = SWAP32(blockName); | |
| 243 | − blockSize = SWAP32(blockSize); | |
| 244 | − | |
| 245 | − switch (blockName) | |
| 246 | − { | |
| 247 | − case 0x434F4D4D: // "COMM" | |
| 248 | − { | |
| 249 | − commPtr = ftell(f); | |
| 250 | − commLen = blockSize; | |
| 251 | − } | |
| 252 | − break; | |
| 253 | − | |
| 254 | − case 0x53534E44: // "SSND" | |
| 255 | − { | |
| 256 | − ssndPtr = ftell(f); | |
| 257 | − ssndLen = blockSize; | |
| 258 | − } | |
| 259 | − break; | |
| 260 | − | |
| 261 | − default: break; | |
| 262 | − } | |
| 263 | − | |
| 264 | − fseek(f, blockSize + (blockSize & 1), SEEK_CUR); | |
| 265 | − } | |
| 266 | − | |
| 267 | − if (commPtr == 0 || commLen < 18 || ssndPtr == 0) | |
| 268 | − { | |
| 269 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 270 | − goto aiffLoadError; | |
| 271 | − } | |
| 272 | − | |
| 273 | − // kludge for some really strange AIFFs | |
| 274 | − if (ssndLen == 0) | |
| 275 | − ssndLen = filesize - ssndPtr; | |
| 276 | − | |
| 277 | − if (ssndPtr+ssndLen > (uint32_t)filesize) | |
| 278 | − ssndLen = filesize - ssndPtr; | |
| 279 | − | |
| 280 | − fseek(f, commPtr, SEEK_SET); | |
| 281 | − fread(&numChannels, 2, 1, f); numChannels = SWAP16(numChannels); | |
| 282 | − fseek(f, 4, SEEK_CUR); | |
| 283 | − fread(&bitDepth, 2, 1, f); bitDepth = SWAP16(bitDepth); | |
| 284 | − fread(sampleRateBytes, 1, 10, f); | |
| 285 | − | |
| 286 | − if (numChannels != 1 && numChannels != 2) | |
| 287 | − { | |
| 288 | − okBoxThreadSafe(0, "System message", "Error loading sample: Unsupported amounts of channels!"); | |
| 289 | − goto aiffLoadError; | |
| 290 | − } | |
| 291 | − | |
| 292 | − if (bitDepth != 8 && bitDepth != 16 && bitDepth != 24 && bitDepth != 32) | |
| 293 | − { | |
| 294 | − okBoxThreadSafe(0, "System message", "Error loading sample: Unsupported bitdepth!"); | |
| 295 | − goto aiffLoadError; | |
| 296 | − } | |
| 297 | − | |
| 298 | − // read compression type (if present) | |
| 299 | − if (commLen > 18) | |
| 300 | − { | |
| 301 | − fread(&compType, 1, 4, f); | |
| 302 | − if (memcmp(compType, "NONE", 4)) | |
| 303 | − { | |
| 304 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 305 | − goto aiffLoadError; | |
| 306 | − } | |
| 307 | − } | |
| 308 | − | |
| 309 | − uint32_t sampleRate = getAIFFRate(sampleRateBytes); | |
| 310 | − | |
| 311 | − // sample data chunk | |
| 312 | − | |
| 313 | − fseek(f, ssndPtr, SEEK_SET); | |
| 314 | − | |
| 315 | − fread(&offset, 4, 1, f); | |
| 316 | − if (offset > 0) | |
| 317 | − { | |
| 318 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 319 | − goto aiffLoadError; | |
| 320 | − } | |
| 321 | − | |
| 322 | − fseek(f, 4, SEEK_CUR); | |
| 323 | − | |
| 324 | − ssndLen -= 8; // don't include offset and blockSize datas | |
| 325 | − | |
| 326 | − uint32_t sampleLength = ssndLen; | |
| 327 | − if (sampleLength > MAX_SAMPLE_LEN) | |
| 328 | − sampleLength = MAX_SAMPLE_LEN; | |
| 329 | − | |
| 330 | − freeTmpSample(&tmpSmp); | |
| 331 | − | |
| 332 | − // read sample data | |
| 333 | − | |
| 334 | − if (bitDepth == 8) | |
| 335 | − { | |
| 336 | − // 8-BIT SIGNED PCM | |
| 337 | − | |
| 338 | − tmpSmp.origPek = (int8_t *)malloc(sampleLength + LOOP_FIX_LEN); | |
| 339 | − if (tmpSmp.origPek == NULL) | |
| 340 | − { | |
| 341 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 342 | − goto aiffLoadError; | |
| 343 | − } | |
| 344 | − | |
| 345 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 346 | − | |
| 347 | − if (fread(tmpSmp.pek, sampleLength, 1, f) != 1) | |
| 348 | − { | |
| 349 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 350 | − goto aiffLoadError; | |
| 351 | − } | |
| 352 | − | |
| 353 | − audioDataS8 = (int8_t *)tmpSmp.pek; | |
| 354 | − | |
| 355 | − // stereo conversion | |
| 356 | − if (numChannels == 2) | |
| 357 | − { | |
| 358 | − sampleLength /= 2; | |
| 359 | − | |
| 360 | − switch (stereoSampleLoadMode) | |
| 361 | − { | |
| 362 | − case STEREO_SAMPLE_READ_LEFT: | |
| 363 | − { | |
| 364 | − for (i = 1; i < sampleLength; i++) | |
| 365 | − audioDataS8[i] = audioDataS8[(i * 2) + 0]; | |
| 366 | − } | |
| 367 | − break; | |
| 368 | − | |
| 369 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 370 | − { | |
| 371 | − len32 = sampleLength - 1; | |
| 372 | − for (i = 0; i < len32; i++) | |
| 373 | − audioDataS8[i] = audioDataS8[(i * 2) + 1]; | |
| 374 | − | |
| 375 | − audioDataS8[i] = 0; | |
| 376 | − } | |
| 377 | − break; | |
| 378 | − | |
| 379 | − default: | |
| 380 | − case STEREO_SAMPLE_CONVERT: | |
| 381 | − { | |
| 382 | − len32 = sampleLength - 1; | |
| 383 | − for (i = 0; i < len32; i++) | |
| 384 | − { | |
| 385 | − smp16 = (audioDataS8[(i * 2) + 0] + audioDataS8[(i * 2) + 1]) >> 1; | |
| 386 | − audioDataS8[i] = (int8_t)smp16; | |
| 387 | − } | |
| 388 | − | |
| 389 | − audioDataS8[i] = 0; | |
| 390 | − } | |
| 391 | − break; | |
| 392 | − } | |
| 393 | − } | |
| 394 | − } | |
| 395 | − else if (bitDepth == 16) | |
| 396 | − { | |
| 397 | − // 16-BIT SIGNED PCM | |
| 398 | − | |
| 399 | − sampleLength /= 2; | |
| 400 | − | |
| 401 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 2) + LOOP_FIX_LEN); | |
| 402 | − if (tmpSmp.origPek == NULL) | |
| 403 | − { | |
| 404 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 405 | − goto aiffLoadError; | |
| 406 | − } | |
| 407 | − | |
| 408 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 409 | − | |
| 410 | − if (fread(tmpSmp.pek, sampleLength, 2, f) != 2) | |
| 411 | − { | |
| 412 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 413 | − goto aiffLoadError; | |
| 414 | − } | |
| 415 | − | |
| 416 | − // fix endianness | |
| 417 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 418 | − for (i = 0; i < sampleLength; i++) | |
| 419 | − audioDataS16[i] = SWAP16(audioDataS16[i]); | |
| 420 | − | |
| 421 | − // stereo conversion | |
| 422 | − if (numChannels == 2) | |
| 423 | − { | |
| 424 | − sampleLength /= 2; | |
| 425 | − | |
| 426 | − switch (stereoSampleLoadMode) | |
| 427 | − { | |
| 428 | − case STEREO_SAMPLE_READ_LEFT: | |
| 429 | − { | |
| 430 | − for (i = 1; i < sampleLength; i++) | |
| 431 | − audioDataS16[i] = audioDataS16[(i * 2) + 0]; | |
| 432 | − } | |
| 433 | − break; | |
| 434 | − | |
| 435 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 436 | − { | |
| 437 | − len32 = sampleLength - 1; | |
| 438 | − for (i = 0; i < len32; i++) | |
| 439 | − audioDataS16[i] = audioDataS16[(i * 2) + 1]; | |
| 440 | − | |
| 441 | − audioDataS16[i] = 0; | |
| 442 | − } | |
| 443 | − break; | |
| 444 | − | |
| 445 | − default: | |
| 446 | − case STEREO_SAMPLE_CONVERT: | |
| 447 | − { | |
| 448 | − len32 = sampleLength - 1; | |
| 449 | − for (i = 0; i < len32; i++) | |
| 450 | − { | |
| 451 | − smp32 = (audioDataS16[(i * 2) + 0] + audioDataS16[(i * 2) + 1]) >> 1; | |
| 452 | − audioDataS16[i] = (int16_t)smp32; | |
| 453 | − } | |
| 454 | − | |
| 455 | − audioDataS16[i] = 0; | |
| 456 | − } | |
| 457 | − break; | |
| 458 | − } | |
| 459 | − } | |
| 460 | − | |
| 461 | − sampleLength *= 2; | |
| 462 | − tmpSmp.typ |= 16; | |
| 463 | − } | |
| 464 | − else if (bitDepth == 24) | |
| 465 | − { | |
| 466 | − // 24-BIT SIGNED PCM | |
| 467 | − | |
| 468 | − sampleLength /= 3; | |
| 469 | − | |
| 470 | − tmpSmp.origPek = (int8_t *)malloc(((sampleLength * 4) * 2) + LOOP_FIX_LEN); | |
| 471 | − if (tmpSmp.origPek == NULL) | |
| 472 | − { | |
| 473 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 474 | − goto aiffLoadError; | |
| 475 | − } | |
| 476 | − | |
| 477 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 478 | − | |
| 479 | − if (fread(&tmpSmp.pek[sampleLength], sampleLength, 3, f) != 3) | |
| 480 | − { | |
| 481 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 482 | − goto aiffLoadError; | |
| 483 | − } | |
| 484 | − | |
| 485 | − audioDataS32 = (int32_t *)tmpSmp.pek; | |
| 486 | − | |
| 487 | − // convert to 32-bit | |
| 488 | − audioDataU8 = (uint8_t *)tmpSmp.pek + sampleLength; | |
| 489 | − for (i = 0; i < sampleLength; i++) | |
| 490 | − { | |
| 491 | − audioDataS32[i] = (audioDataU8[0] << 24) | (audioDataU8[1] << 16) | (audioDataU8[2] << 8); | |
| 492 | − audioDataU8 += 3; | |
| 493 | − } | |
| 494 | − | |
| 495 | − // stereo conversion | |
| 496 | − if (numChannels == 2) | |
| 497 | − { | |
| 498 | − sampleLength /= 2; | |
| 499 | − | |
| 500 | − switch (stereoSampleLoadMode) | |
| 501 | − { | |
| 502 | − case STEREO_SAMPLE_READ_LEFT: | |
| 503 | − { | |
| 504 | − for (i = 1; i < sampleLength; i++) | |
| 505 | − audioDataS32[i] = audioDataS32[(i * 2) + 0]; | |
| 506 | − } | |
| 507 | − break; | |
| 508 | − | |
| 509 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 510 | − { | |
| 511 | − len32 = sampleLength - 1; | |
| 512 | − for (i = 0; i < len32; i++) | |
| 513 | − audioDataS32[i] = audioDataS32[(i * 2) + 1]; | |
| 514 | − | |
| 515 | − audioDataS32[i] = 0; | |
| 516 | − } | |
| 517 | − break; | |
| 518 | − | |
| 519 | − default: | |
| 520 | − case STEREO_SAMPLE_CONVERT: | |
| 521 | − { | |
| 522 | − len32 = sampleLength - 1; | |
| 523 | − for (i = 0; i < len32; i++) | |
| 524 | − { | |
| 525 | − smp64 = audioDataS32[(i * 2) + 0]; | |
| 526 | − smp64 += audioDataS32[(i * 2) + 1]; | |
| 527 | − smp64 >>= 1; | |
| 528 | − | |
| 529 | − audioDataS32[i] = (int32_t)smp64; | |
| 530 | − } | |
| 531 | − | |
| 532 | − audioDataS32[i] = 0; | |
| 533 | − } | |
| 534 | − break; | |
| 535 | − } | |
| 536 | − } | |
| 537 | − | |
| 538 | − normalize32bitSigned(audioDataS32, sampleLength); | |
| 539 | − | |
| 540 | − // downscale to 16-bit (ultra fast method!) | |
| 541 | − | |
| 542 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 543 | − audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; | |
| 544 | − | |
| 545 | − for (i = 0; i < sampleLength; i++) | |
| 546 | − { | |
| 547 | − audioDataS16[i] = audioDataS16_2[i]; | |
| 548 | − audioDataS16_2++; | |
| 549 | − } | |
| 550 | − | |
| 551 | − sampleLength *= 2; | |
| 552 | − tmpSmp.typ |= 16; | |
| 553 | − } | |
| 554 | − else if (bitDepth == 32) | |
| 555 | − { | |
| 556 | − // 32-BIT SIGNED PCM | |
| 557 | − | |
| 558 | − sampleLength /= 4; | |
| 559 | − | |
| 560 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 4) + LOOP_FIX_LEN); | |
| 561 | − if (tmpSmp.origPek == NULL) | |
| 562 | − { | |
| 563 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 564 | − goto aiffLoadError; | |
| 565 | − } | |
| 566 | − | |
| 567 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 568 | − | |
| 569 | − if (fread(tmpSmp.pek, sampleLength, 4, f) != 4) | |
| 570 | − { | |
| 571 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 572 | − goto aiffLoadError; | |
| 573 | − } | |
| 574 | − | |
| 575 | − // fix endianness | |
| 576 | − audioDataS32 = (int32_t *)tmpSmp.pek; | |
| 577 | − for (i = 0; i < sampleLength; i++) | |
| 578 | − audioDataS32[i] = SWAP32(audioDataS32[i]); | |
| 579 | − | |
| 580 | − // stereo conversion | |
| 581 | − if (numChannels == 2) | |
| 582 | − { | |
| 583 | − sampleLength /= 2; | |
| 584 | − | |
| 585 | − switch (stereoSampleLoadMode) | |
| 586 | − { | |
| 587 | − case STEREO_SAMPLE_READ_LEFT: | |
| 588 | − { | |
| 589 | − for (i = 1; i < sampleLength; i++) | |
| 590 | − audioDataS32[i] = audioDataS32[(i * 2) + 0]; | |
| 591 | − } | |
| 592 | − break; | |
| 593 | − | |
| 594 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 595 | − { | |
| 596 | − len32 = sampleLength - 1; | |
| 597 | − for (i = 0; i < len32; i++) | |
| 598 | − audioDataS32[i] = audioDataS32[(i * 2) + 1]; | |
| 599 | − | |
| 600 | − audioDataS32[i] = 0; | |
| 601 | − } | |
| 602 | − break; | |
| 603 | − | |
| 604 | − default: | |
| 605 | − case STEREO_SAMPLE_CONVERT: | |
| 606 | − { | |
| 607 | − len32 = sampleLength - 1; | |
| 608 | − for (i = 0; i < len32; i++) | |
| 609 | − { | |
| 610 | − smp64 = audioDataS32[(i * 2) + 0]; | |
| 611 | − smp64 += audioDataS32[(i * 2) + 1]; | |
| 612 | − smp64 >>= 1; | |
| 613 | − | |
| 614 | − audioDataS32[i] = (int32_t)smp64; | |
| 615 | − } | |
| 616 | − | |
| 617 | − audioDataS32[i] = 0; | |
| 618 | − } | |
| 619 | − break; | |
| 620 | − } | |
| 621 | − } | |
| 622 | − | |
| 623 | − normalize32bitSigned(audioDataS32, sampleLength); | |
| 624 | − | |
| 625 | − // downscale to 16-bit (ultra fast method!) | |
| 626 | − | |
| 627 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 628 | − audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; | |
| 629 | − | |
| 630 | − for (i = 0; i < sampleLength; i++) | |
| 631 | − { | |
| 632 | − audioDataS16[i] = audioDataS16_2[i]; | |
| 633 | − audioDataS16_2++; | |
| 634 | − } | |
| 635 | − | |
| 636 | − sampleLength *= 2; | |
| 637 | − tmpSmp.typ |= 16; | |
| 638 | − } | |
| 639 | − | |
| 640 | − // adjust memory needed | |
| 641 | − int8_t *newPtr = (int8_t *)realloc(tmpSmp.origPek, sampleLength + LOOP_FIX_LEN); | |
| 642 | − if (newPtr != NULL) | |
| 643 | − { | |
| 644 | − tmpSmp.origPek = newPtr; | |
| 645 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 646 | − } | |
| 647 | − | |
| 648 | − // set sample attributes | |
| 649 | − tmpSmp.len = sampleLength; | |
| 650 | − tmpSmp.vol = 64; | |
| 651 | − tmpSmp.pan = 128; | |
| 652 | − | |
| 653 | − tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag); | |
| 654 | − | |
| 655 | − // set sample name | |
| 656 | − char *tmpFilename = unicharToCp437(filename, true); | |
| 657 | − if (tmpFilename != NULL) | |
| 658 | − { | |
| 659 | − j = (int32_t)strlen(tmpFilename); | |
| 660 | − while (j--) | |
| 661 | − { | |
| 662 | − if (tmpFilename[j] == DIR_DELIMITER) | |
| 663 | − break; | |
| 664 | − } | |
| 665 | − | |
| 666 | − char *tmpPtr = tmpFilename; | |
| 667 | − if (j > 0) | |
| 668 | − tmpPtr += j + 1; | |
| 669 | − | |
| 670 | − sanitizeFilename(tmpPtr); | |
| 671 | − | |
| 672 | − uint32_t filenameLen = (uint32_t)strlen(tmpPtr); | |
| 673 | − for (i = 0; i < 22; i++) | |
| 674 | − { | |
| 675 | − if (i < filenameLen) | |
| 676 | − tmpSmp.name[i] = tmpPtr[i]; | |
| 677 | − else | |
| 678 | − tmpSmp.name[i] = '\0'; | |
| 679 | − } | |
| 680 | − | |
| 681 | − free(tmpFilename); | |
| 682 | − } | |
| 683 | − | |
| 684 | − fclose(f); | |
| 685 | − | |
| 686 | − lockMixerCallback(); | |
| 687 | − if (loadAsInstrFlag) // if loaded in instrument mode | |
| 688 | − { | |
| 689 | − freeInstr(editor.curInstr); | |
| 690 | − memset(song.instrName[editor.curInstr], 0, 23); | |
| 691 | − } | |
| 692 | − | |
| 693 | − if (instr[editor.curInstr] == NULL) | |
| 694 | − allocateInstr(editor.curInstr); | |
| 695 | − | |
| 696 | − if (instr[editor.curInstr] != NULL) | |
| 697 | − { | |
| 698 | − sampleTyp *s = &instr[editor.curInstr]->samp[sampleSlot]; | |
| 699 | − | |
| 700 | − freeSample(editor.curInstr, sampleSlot); | |
| 701 | − memcpy(s, &tmpSmp, sizeof (sampleTyp)); | |
| 702 | − fixSample(s); | |
| 703 | − } | |
| 704 | − else | |
| 705 | − { | |
| 706 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 707 | − goto aiffLoadError; | |
| 708 | − } | |
| 709 | − unlockMixerCallback(); | |
| 710 | − | |
| 711 | − fixSampleName(editor.curInstr); | |
| 712 | − setSongModifiedFlag(); | |
| 713 | − stereoSampleLoadMode = -1; | |
| 714 | − | |
| 715 | − // also sets mouse busy to false when done | |
| 716 | − editor.updateCurSmp = true; | |
| 717 | − | |
| 718 | − return true; | |
| 719 | − | |
| 720 | −aiffLoadError: | |
| 721 | − if (f != NULL) fclose(f); | |
| 722 | − if (tmpSmp.origPek != NULL) free(tmpSmp.origPek); | |
| 723 | − | |
| 724 | − stereoSampleLoadMode = -1; | |
| 725 | − sampleIsLoading = false; | |
| 726 | − | |
| 727 | − return false; | |
| 728 | − | |
| 729 | − (void)ptr; | |
| 730 | −} | |
| 731 | − | |
| 732 | −static int32_t SDLCALL loadIFFSample(void *ptr) | |
| 733 | −{ | |
| 734 | − char hdr[4+1]; | |
| 735 | − uint8_t i; | |
| 736 | − int32_t j; | |
| 737 | − uint32_t blockName, blockSize; | |
| 738 | − sampleTyp tmpSmp; | |
| 739 | − | |
| 740 | − // this is important for the "goto" on load error | |
| 741 | − FILE *f = NULL; | |
| 742 | − memset(&tmpSmp, 0, sizeof (tmpSmp)); | |
| 743 | − | |
| 744 | − if (editor.tmpFilenameU == NULL) | |
| 745 | − { | |
| 746 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 747 | − goto iffLoadError; | |
| 748 | − } | |
| 749 | − | |
| 750 | − UNICHAR *filename = editor.tmpFilenameU; | |
| 751 | − | |
| 752 | − f = UNICHAR_FOPEN(filename, "rb"); | |
| 753 | − if (f == NULL) | |
| 754 | − { | |
| 755 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 756 | − goto iffLoadError; | |
| 757 | − } | |
| 758 | − | |
| 759 | − fseek(f, 0, SEEK_END); | |
| 760 | − int32_t filesize = ftell(f); | |
| 761 | − if (filesize < 12) | |
| 762 | − { | |
| 763 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 764 | − goto iffLoadError; | |
| 765 | − } | |
| 766 | − | |
| 767 | − fseek(f, 8, SEEK_SET); | |
| 768 | − fread(hdr, 1, 4, f); | |
| 769 | − hdr[4] = '\0'; | |
| 770 | − bool is16Bit = !strncmp(hdr, "16SV", 4); | |
| 771 | − | |
| 772 | − uint32_t sampleLength = 0; | |
| 773 | − uint32_t sampleVol = 64; | |
| 774 | − uint32_t sampleLoopStart = 0; | |
| 775 | − uint32_t sampleLoopLength = 0; | |
| 776 | − uint16_t sampleRate = 16726; | |
| 777 | − | |
| 778 | − uint32_t vhdrPtr = 0; | |
| 779 | − uint32_t vhdrLen = 0; | |
| 780 | − uint32_t bodyPtr = 0; | |
| 781 | − uint32_t bodyLen = 0; | |
| 782 | − uint32_t namePtr = 0; | |
| 783 | − uint32_t nameLen = 0; | |
| 784 | − | |
| 785 | − fseek(f, 12, SEEK_SET); | |
| 786 | − while (!feof(f) && ftell(f) < filesize-12) | |
| 787 | − { | |
| 788 | − fread(&blockName, 4, 1, f); if (feof(f)) break; | |
| 789 | − fread(&blockSize, 4, 1, f); if (feof(f)) break; | |
| 790 | − | |
| 791 | − blockName = SWAP32(blockName); | |
| 792 | − blockSize = SWAP32(blockSize); | |
| 793 | − | |
| 794 | − switch (blockName) | |
| 795 | − { | |
| 796 | − case 0x56484452: // VHDR | |
| 797 | − { | |
| 798 | − vhdrPtr = ftell(f); | |
| 799 | − vhdrLen = blockSize; | |
| 800 | − } | |
| 801 | − break; | |
| 802 | − | |
| 803 | − case 0x4E414D45: // NAME | |
| 804 | − { | |
| 805 | − namePtr = ftell(f); | |
| 806 | − nameLen = blockSize; | |
| 807 | − } | |
| 808 | − break; | |
| 809 | − | |
| 810 | − case 0x424F4459: // BODY | |
| 811 | − { | |
| 812 | − bodyPtr = ftell(f); | |
| 813 | − bodyLen = blockSize; | |
| 814 | − } | |
| 815 | − break; | |
| 816 | − | |
| 817 | − default: break; | |
| 818 | − } | |
| 819 | − | |
| 820 | − fseek(f, blockSize + (blockSize & 1), SEEK_CUR); | |
| 821 | − } | |
| 822 | − | |
| 823 | − if (vhdrPtr == 0 || vhdrLen < 20 || bodyPtr == 0) | |
| 824 | − { | |
| 825 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 826 | − goto iffLoadError; | |
| 827 | − } | |
| 828 | − | |
| 829 | − // kludge for some really strange IFFs | |
| 830 | − if (bodyLen == 0) | |
| 831 | − bodyLen = filesize - bodyPtr; | |
| 832 | − | |
| 833 | − if (bodyPtr+bodyLen > (uint32_t)filesize) | |
| 834 | − bodyLen = filesize - bodyPtr; | |
| 835 | − | |
| 836 | − fseek(f, vhdrPtr, SEEK_SET); | |
| 837 | − fread(&sampleLoopStart, 4, 1, f); sampleLoopStart = SWAP32(sampleLoopStart); | |
| 838 | − fread(&sampleLoopLength, 4, 1, f); sampleLoopLength = SWAP32(sampleLoopLength); | |
| 839 | − fseek(f, 4, SEEK_CUR); | |
| 840 | − fread(&sampleRate, 2, 1, f); sampleRate = SWAP16(sampleRate); | |
| 841 | − fseek(f, 1, SEEK_CUR); | |
| 842 | − | |
| 843 | − if (fgetc(f) != 0) // sample type | |
| 844 | − { | |
| 845 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported!"); | |
| 846 | − goto iffLoadError; | |
| 847 | − } | |
| 848 | − | |
| 849 | − fread(&sampleVol, 4, 1, f); sampleVol = SWAP32(sampleVol); | |
| 850 | − if (sampleVol > 65535) | |
| 851 | − sampleVol = 65535; | |
| 852 | − | |
| 853 | − sampleVol = (int32_t)((sampleVol / 1024.0) + 0.5); | |
| 854 | − if (sampleVol > 64) | |
| 855 | − sampleVol = 64; | |
| 856 | − | |
| 857 | − sampleLength = bodyLen; | |
| 858 | − if (sampleLength > MAX_SAMPLE_LEN) | |
| 859 | − sampleLength = MAX_SAMPLE_LEN; | |
| 860 | − | |
| 861 | − if (sampleLoopStart >= MAX_SAMPLE_LEN || sampleLoopLength > MAX_SAMPLE_LEN) | |
| 862 | − { | |
| 863 | − sampleLoopStart = 0; | |
| 864 | − sampleLoopLength = 0; | |
| 865 | − } | |
| 866 | − | |
| 867 | − if (sampleLoopStart+sampleLoopLength > sampleLength) | |
| 868 | − { | |
| 869 | − sampleLoopStart = 0; | |
| 870 | − sampleLoopLength = 0; | |
| 871 | − } | |
| 872 | − | |
| 873 | − if (sampleLoopStart > sampleLength-2) | |
| 874 | − { | |
| 875 | − sampleLoopStart = 0; | |
| 876 | − sampleLoopLength = 0; | |
| 877 | − } | |
| 878 | − | |
| 879 | − tmpSmp.pan = 128; | |
| 880 | − tmpSmp.vol = 64; | |
| 881 | − | |
| 882 | − tmpSmp.origPek = (int8_t *)malloc(sampleLength + LOOP_FIX_LEN); | |
| 883 | − if (tmpSmp.origPek == NULL) | |
| 884 | − { | |
| 885 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 886 | − goto iffLoadError; | |
| 887 | − } | |
| 888 | − | |
| 889 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 890 | − | |
| 891 | − fseek(f, bodyPtr, SEEK_SET); | |
| 892 | − if (fread(tmpSmp.pek, sampleLength, 1, f) != 1) | |
| 893 | − { | |
| 894 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 895 | − goto iffLoadError; | |
| 896 | − } | |
| 897 | − | |
| 898 | − // set sample attributes | |
| 899 | − tmpSmp.len = sampleLength; | |
| 900 | − | |
| 901 | − if (sampleLoopLength > 2) | |
| 902 | − { | |
| 903 | − tmpSmp.repS = sampleLoopStart; | |
| 904 | − tmpSmp.repL = sampleLoopLength; | |
| 905 | − tmpSmp.typ |= 1; | |
| 906 | − } | |
| 907 | − | |
| 908 | − if (is16Bit) | |
| 909 | − { | |
| 910 | − tmpSmp.len &= 0xFFFFFFFE; | |
| 911 | − tmpSmp.repS &= 0xFFFFFFFE; | |
| 912 | − tmpSmp.repL &= 0xFFFFFFFE; | |
| 913 | − tmpSmp.typ |= 16; | |
| 914 | − } | |
| 915 | − | |
| 916 | − tmpSmp.vol = (uint8_t)sampleVol; | |
| 917 | − tmpSmp.pan = 128; | |
| 918 | − | |
| 919 | − tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag); | |
| 920 | − | |
| 921 | − // set name | |
| 922 | − if (namePtr != 0 && nameLen > 0) | |
| 923 | − { | |
| 924 | − fseek(f, namePtr, SEEK_SET); | |
| 925 | − if (nameLen > 21) | |
| 926 | − { | |
| 927 | − tmpSmp.name[21] = '\0'; | |
| 928 | − fread(tmpSmp.name, 1, 21, f); | |
| 929 | − } | |
| 930 | − else | |
| 931 | − { | |
| 932 | − memset(tmpSmp.name, 0, 22); | |
| 933 | − fread(tmpSmp.name, 1, nameLen, f); | |
| 934 | − } | |
| 935 | − } | |
| 936 | − else | |
| 937 | − { | |
| 938 | − // set sample name from filename if we didn't load name from .wav | |
| 939 | − char *tmpFilename = unicharToCp437(filename, true); | |
| 940 | − if (tmpFilename != NULL) | |
| 941 | − { | |
| 942 | − j = (int32_t)strlen(tmpFilename); | |
| 943 | − while (j--) | |
| 944 | − { | |
| 945 | − if (tmpFilename[j] == DIR_DELIMITER) | |
| 946 | − break; | |
| 947 | − } | |
| 948 | − | |
| 949 | − char *tmpPtr = tmpFilename; | |
| 950 | − if (j > 0) | |
| 951 | − tmpPtr += j + 1; | |
| 952 | − | |
| 953 | − sanitizeFilename(tmpPtr); | |
| 954 | − | |
| 955 | − uint32_t filenameLen = (uint32_t)strlen(tmpPtr); | |
| 956 | − for (i = 0; i < 22; i++) | |
| 957 | − { | |
| 958 | − if (i < filenameLen) | |
| 959 | − tmpSmp.name[i] = tmpPtr[i]; | |
| 960 | − else | |
| 961 | − tmpSmp.name[i] = '\0'; | |
| 962 | − } | |
| 963 | − | |
| 964 | − free(tmpFilename); | |
| 965 | − } | |
| 966 | − } | |
| 967 | − | |
| 968 | − fclose(f); | |
| 969 | − | |
| 970 | − lockMixerCallback(); | |
| 971 | − if (loadAsInstrFlag) // if loaded in instrument mode | |
| 972 | − { | |
| 973 | − freeInstr(editor.curInstr); | |
| 974 | − memset(song.instrName[editor.curInstr], 0, 23); | |
| 975 | − } | |
| 976 | − | |
| 977 | − if (instr[editor.curInstr] == NULL) | |
| 978 | − allocateInstr(editor.curInstr); | |
| 979 | − | |
| 980 | − if (instr[editor.curInstr] != NULL) | |
| 981 | − { | |
| 982 | − sampleTyp *s = &instr[editor.curInstr]->samp[sampleSlot]; | |
| 983 | − | |
| 984 | − freeSample(editor.curInstr, sampleSlot); | |
| 985 | − memcpy(s, &tmpSmp, sizeof (sampleTyp)); | |
| 986 | − fixSample(s); | |
| 987 | − } | |
| 988 | − else | |
| 989 | − { | |
| 990 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 991 | − goto iffLoadError; | |
| 992 | − } | |
| 993 | − unlockMixerCallback(); | |
| 994 | − | |
| 995 | − fixSampleName(editor.curInstr); | |
| 996 | − setSongModifiedFlag(); | |
| 997 | − stereoSampleLoadMode = -1; | |
| 998 | − | |
| 999 | − // also sets mouse busy to false when done | |
| 1000 | − editor.updateCurSmp = true; | |
| 1001 | − | |
| 1002 | − return true; | |
| 1003 | − | |
| 1004 | −iffLoadError: | |
| 1005 | − if (f != NULL) fclose(f); | |
| 1006 | − if (tmpSmp.origPek != NULL) free(tmpSmp.origPek); | |
| 1007 | − | |
| 1008 | − stereoSampleLoadMode = -1; | |
| 1009 | − sampleIsLoading = false; | |
| 1010 | − | |
| 1011 | − return false; | |
| 1012 | − | |
| 1013 | − (void)ptr; | |
| 1014 | −} | |
| 1015 | − | |
| 1016 | −static int32_t SDLCALL loadRawSample(void *ptr) | |
| 1017 | −{ | |
| 1018 | − int32_t j; | |
| 1019 | − uint32_t i; | |
| 1020 | − sampleTyp tmpSmp; | |
| 1021 | − | |
| 1022 | − // this is important for the "goto" on load error | |
| 1023 | − FILE *f = NULL; | |
| 1024 | − memset(&tmpSmp, 0, sizeof (tmpSmp)); | |
| 1025 | − | |
| 1026 | − if (editor.tmpFilenameU == NULL) | |
| 1027 | − { | |
| 1028 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1029 | − goto rawLoadError; | |
| 1030 | − } | |
| 1031 | − | |
| 1032 | − UNICHAR *filename = editor.tmpFilenameU; | |
| 1033 | − | |
| 1034 | − f = UNICHAR_FOPEN(filename, "rb"); | |
| 1035 | − if (f == NULL) | |
| 1036 | − { | |
| 1037 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1038 | − goto rawLoadError; | |
| 1039 | − } | |
| 1040 | − | |
| 1041 | − fseek(f, 0, SEEK_END); | |
| 1042 | − uint32_t filesize = ftell(f); | |
| 1043 | − rewind(f); | |
| 1044 | − | |
| 1045 | − if (filesize > MAX_SAMPLE_LEN) | |
| 1046 | − filesize = MAX_SAMPLE_LEN; | |
| 1047 | − | |
| 1048 | − if (filesize == 0) | |
| 1049 | − { | |
| 1050 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 1051 | − goto rawLoadError; | |
| 1052 | − } | |
| 1053 | − | |
| 1054 | − tmpSmp.pan = 128; | |
| 1055 | − tmpSmp.vol = 64; | |
| 1056 | − | |
| 1057 | − tmpSmp.origPek = (int8_t *)malloc(filesize + LOOP_FIX_LEN); | |
| 1058 | − if (tmpSmp.origPek == NULL) | |
| 1059 | − { | |
| 1060 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1061 | − goto rawLoadError; | |
| 1062 | − } | |
| 1063 | − | |
| 1064 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1065 | − | |
| 1066 | − if (fread(tmpSmp.pek, filesize, 1, f) != 1) | |
| 1067 | − { | |
| 1068 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1069 | − goto rawLoadError; | |
| 1070 | − } | |
| 1071 | − | |
| 1072 | − fclose(f); | |
| 1073 | − | |
| 1074 | − char *tmpFilename = unicharToCp437(filename, true); | |
| 1075 | − if (tmpFilename != NULL) | |
| 1076 | − { | |
| 1077 | − j = (int32_t)strlen(tmpFilename); | |
| 1078 | − while (j--) | |
| 1079 | − { | |
| 1080 | − if (tmpFilename[j] == DIR_DELIMITER) | |
| 1081 | − break; | |
| 1082 | − } | |
| 1083 | − | |
| 1084 | − char *tmpPtr = tmpFilename; | |
| 1085 | − if (j > 0) | |
| 1086 | − tmpPtr += j + 1; | |
| 1087 | − | |
| 1088 | − sanitizeFilename(tmpPtr); | |
| 1089 | − | |
| 1090 | − uint32_t filenameLen = (uint32_t)strlen(tmpPtr); | |
| 1091 | − for (i = 0; i < 22; i++) | |
| 1092 | − { | |
| 1093 | − if (i < filenameLen) | |
| 1094 | − tmpSmp.name[i] = tmpPtr[i]; | |
| 1095 | − else | |
| 1096 | − tmpSmp.name[i] = '\0'; | |
| 1097 | − } | |
| 1098 | − | |
| 1099 | − free(tmpFilename); | |
| 1100 | − } | |
| 1101 | − | |
| 1102 | − tmpSmp.len = filesize; | |
| 1103 | − tmpSmp.vol = 64; | |
| 1104 | − tmpSmp.pan = 128; | |
| 1105 | − | |
| 1106 | − lockMixerCallback(); | |
| 1107 | − if (loadAsInstrFlag) // if loaded in instrument mode | |
| 1108 | − { | |
| 1109 | − freeInstr(editor.curInstr); | |
| 1110 | − memset(song.instrName[editor.curInstr], 0, 23); | |
| 1111 | − } | |
| 1112 | − | |
| 1113 | − if (instr[editor.curInstr] == NULL) | |
| 1114 | − allocateInstr(editor.curInstr); | |
| 1115 | − | |
| 1116 | − if (instr[editor.curInstr] != NULL) | |
| 1117 | − { | |
| 1118 | − sampleTyp *s = &instr[editor.curInstr]->samp[sampleSlot]; | |
| 1119 | − | |
| 1120 | − freeSample(editor.curInstr, sampleSlot); | |
| 1121 | − memcpy(s, &tmpSmp, sizeof (sampleTyp)); | |
| 1122 | − fixSample(s); | |
| 1123 | − } | |
| 1124 | − else | |
| 1125 | − { | |
| 1126 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1127 | − goto rawLoadError; | |
| 1128 | − } | |
| 1129 | − unlockMixerCallback(); | |
| 1130 | − | |
| 1131 | − fixSampleName(editor.curInstr); | |
| 1132 | − setSongModifiedFlag(); | |
| 1133 | − stereoSampleLoadMode = -1; | |
| 1134 | − | |
| 1135 | − // also sets mouse busy to false when done | |
| 1136 | − editor.updateCurSmp = true; | |
| 1137 | − | |
| 1138 | − return true; | |
| 1139 | − | |
| 1140 | −rawLoadError: | |
| 1141 | − if (f != NULL) fclose(f); | |
| 1142 | − if (tmpSmp.origPek != NULL) free(tmpSmp.origPek); | |
| 1143 | − | |
| 1144 | − stereoSampleLoadMode = -1; | |
| 1145 | − sampleIsLoading = false; | |
| 1146 | − | |
| 1147 | − return false; | |
| 1148 | − | |
| 1149 | − (void)ptr; | |
| 1150 | −} | |
| 1151 | − | |
| 1152 | −static int32_t SDLCALL loadWAVSample(void *ptr) | |
| 1153 | −{ | |
| 1154 | − char chr, *tmpFilename, *tmpPtr; | |
| 1155 | − int8_t *newPtr; | |
| 1156 | − uint8_t *audioDataU8; | |
| 1157 | − int16_t *audioDataS16, *audioDataS16_2, *ptr16; | |
| 1158 | − uint16_t audioFormat, numChannels, bitsPerSample, tempPan, tempVol; | |
| 1159 | − int32_t j, *audioDataS32, smp32; | |
| 1160 | − uint32_t filenameLen, i, sampleRate, chunkID, chunkSize, sampleLength, filesize; | |
| 1161 | − uint32_t numLoops, loopType, loopStart, loopEnd, bytesRead, endOfChunk, dataPtr, dataLen, fmtPtr; | |
| 1162 | − uint32_t fmtLen, inamPtr, inamLen, smplPtr, smplLen, xtraPtr, xtraLen, xtraFlags, len32; | |
| 1163 | − int64_t smp64; | |
| 1164 | − float *fAudioDataFloat; | |
| 1165 | − double *dAudioDataDouble; | |
| 1166 | − sampleTyp tmpSmp, *s; | |
| 1167 | − | |
| 1168 | − // this is important for the "goto" on load error | |
| 1169 | − FILE *f = NULL; | |
| 1170 | − memset(&tmpSmp, 0, sizeof (tmpSmp)); | |
| 1171 | − | |
| 1172 | − // zero out chunk pointers and lengths | |
| 1173 | − fmtPtr = 0; fmtLen = 0; | |
| 1174 | − dataPtr = 0; dataLen = 0; | |
| 1175 | − inamPtr = 0; inamLen = 0; | |
| 1176 | − xtraPtr = 0; xtraLen = 0; | |
| 1177 | − smplPtr = 0; smplLen = 0; | |
| 1178 | − | |
| 1179 | − if (editor.tmpFilenameU == NULL) | |
| 1180 | − { | |
| 1181 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1182 | − goto wavLoadError; | |
| 1183 | − } | |
| 1184 | − | |
| 1185 | − UNICHAR *filename = editor.tmpFilenameU; | |
| 1186 | − | |
| 1187 | − f = UNICHAR_FOPEN(filename, "rb"); | |
| 1188 | − if (f == NULL) | |
| 1189 | − { | |
| 1190 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1191 | − goto wavLoadError; | |
| 1192 | − } | |
| 1193 | − | |
| 1194 | − // get and check filesize | |
| 1195 | − fseek(f, 0, SEEK_END); | |
| 1196 | − filesize = ftell(f); | |
| 1197 | − if (filesize < 12) | |
| 1198 | − { | |
| 1199 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 1200 | − goto wavLoadError; | |
| 1201 | − } | |
| 1202 | − | |
| 1203 | − // look for wanted chunks and set up pointers + lengths | |
| 1204 | − fseek(f, 12, SEEK_SET); | |
| 1205 | − | |
| 1206 | − bytesRead = 0; | |
| 1207 | − while (!feof(f) && bytesRead < filesize-12) | |
| 1208 | − { | |
| 1209 | − fread(&chunkID, 4, 1, f); if (feof(f)) break; | |
| 1210 | − fread(&chunkSize, 4, 1, f); if (feof(f)) break; | |
| 1211 | − | |
| 1212 | − endOfChunk = (ftell(f) + chunkSize) + (chunkSize & 1); | |
| 1213 | − switch (chunkID) | |
| 1214 | − { | |
| 1215 | − case 0x20746D66: // "fmt " | |
| 1216 | − { | |
| 1217 | − fmtPtr = ftell(f); | |
| 1218 | − fmtLen = chunkSize; | |
| 1219 | − } | |
| 1220 | − break; | |
| 1221 | − | |
| 1222 | − case 0x61746164: // "data" | |
| 1223 | − { | |
| 1224 | − dataPtr = ftell(f); | |
| 1225 | − dataLen = chunkSize; | |
| 1226 | − } | |
| 1227 | − break; | |
| 1228 | − | |
| 1229 | − case 0x5453494C: // "LIST" | |
| 1230 | − { | |
| 1231 | − if (chunkSize >= 4) | |
| 1232 | − { | |
| 1233 | − fread(&chunkID, 4, 1, f); | |
| 1234 | − if (chunkID == 0x4F464E49) // "INFO" | |
| 1235 | − { | |
| 1236 | − bytesRead = 0; | |
| 1237 | − while (!feof(f) && bytesRead < chunkSize) | |
| 1238 | − { | |
| 1239 | − fread(&chunkID, 4, 1, f); | |
| 1240 | − fread(&chunkSize, 4, 1, f); | |
| 1241 | − | |
| 1242 | − switch (chunkID) | |
| 1243 | − { | |
| 1244 | − case 0x4D414E49: // "INAM" | |
| 1245 | − { | |
| 1246 | − inamPtr = ftell(f); | |
| 1247 | − inamLen = chunkSize; | |
| 1248 | − } | |
| 1249 | − break; | |
| 1250 | − | |
| 1251 | − default: break; | |
| 1252 | − } | |
| 1253 | − | |
| 1254 | − bytesRead += (chunkSize + (chunkSize & 1)); | |
| 1255 | − } | |
| 1256 | − } | |
| 1257 | − } | |
| 1258 | − } | |
| 1259 | − break; | |
| 1260 | − | |
| 1261 | − case 0x61727478: // "xtra" | |
| 1262 | − { | |
| 1263 | − xtraPtr = ftell(f); | |
| 1264 | − xtraLen = chunkSize; | |
| 1265 | − } | |
| 1266 | − break; | |
| 1267 | − | |
| 1268 | − case 0x6C706D73: // "smpl" | |
| 1269 | − { | |
| 1270 | − smplPtr = ftell(f); | |
| 1271 | − smplLen = chunkSize; | |
| 1272 | − } | |
| 1273 | − break; | |
| 1274 | − | |
| 1275 | − default: break; | |
| 1276 | − } | |
| 1277 | − | |
| 1278 | − bytesRead += (chunkSize + (chunkSize & 1)); | |
| 1279 | − fseek(f, endOfChunk, SEEK_SET); | |
| 1280 | − } | |
| 1281 | − | |
| 1282 | − // we need at least "fmt " and "data" - check if we found them sanely | |
| 1283 | − if ((fmtPtr == 0 || fmtLen < 16) || (dataPtr == 0 || dataLen == 0)) | |
| 1284 | − { | |
| 1285 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 1286 | − goto wavLoadError; | |
| 1287 | − } | |
| 1288 | − | |
| 1289 | − // ---- READ "fmt " CHUNK ---- | |
| 1290 | − fseek(f, fmtPtr, SEEK_SET); | |
| 1291 | − fread(&audioFormat, 2, 1, f); | |
| 1292 | − fread(&numChannels, 2, 1, f); | |
| 1293 | − fread(&sampleRate, 4, 1, f); | |
| 1294 | − fseek(f, 6, SEEK_CUR); // unneeded | |
| 1295 | − fread(&bitsPerSample, 2, 1, f); | |
| 1296 | − sampleLength = dataLen; | |
| 1297 | − // --------------------------- | |
| 1298 | − | |
| 1299 | − // test if the WAV is compatible with our loader | |
| 1300 | − | |
| 1301 | − if (sampleRate == 0 || sampleLength == 0 || sampleLength >= filesize) | |
| 1302 | − { | |
| 1303 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported or is invalid!"); | |
| 1304 | − goto wavLoadError; | |
| 1305 | − } | |
| 1306 | − | |
| 1307 | − if (audioFormat != WAV_FORMAT_PCM && audioFormat != WAV_FORMAT_IEEE_FLOAT) | |
| 1308 | − { | |
| 1309 | − okBoxThreadSafe(0, "System message", "Error loading sample: The sample is not supported!"); | |
| 1310 | − goto wavLoadError; | |
| 1311 | − } | |
| 1312 | − | |
| 1313 | − if (numChannels == 0 || numChannels > 2) | |
| 1314 | − { | |
| 1315 | − okBoxThreadSafe(0, "System message", "Error loading sample: Unsupported number of channels!"); | |
| 1316 | − goto wavLoadError; | |
| 1317 | − } | |
| 1318 | − | |
| 1319 | − if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample != 32 && bitsPerSample != 64) | |
| 1320 | − { | |
| 1321 | − okBoxThreadSafe(0, "System message", "Error loading sample: Unsupported bitdepth!"); | |
| 1322 | − goto wavLoadError; | |
| 1323 | − } | |
| 1324 | − | |
| 1325 | − if (bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 24 && bitsPerSample != 32 && bitsPerSample != 64) | |
| 1326 | − { | |
| 1327 | − okBoxThreadSafe(0, "System message", "Error loading sample: Unsupported bitdepth!"); | |
| 1328 | − goto wavLoadError; | |
| 1329 | − } | |
| 1330 | − | |
| 1331 | − // ---- READ SAMPLE DATA ---- | |
| 1332 | − fseek(f, dataPtr, SEEK_SET); | |
| 1333 | − | |
| 1334 | − s = &instr[editor.curInstr]->samp[editor.curSmp]; | |
| 1335 | − tmpSmp.pan = 128; | |
| 1336 | − tmpSmp.vol = 64; | |
| 1337 | − | |
| 1338 | − if (sampleLength > MAX_SAMPLE_LEN) | |
| 1339 | − sampleLength = MAX_SAMPLE_LEN; | |
| 1340 | − | |
| 1341 | − if (bitsPerSample == 8) // 8-BIT INTEGER SAMPLE | |
| 1342 | − { | |
| 1343 | − tmpSmp.origPek = (int8_t *)malloc(sampleLength + LOOP_FIX_LEN); | |
| 1344 | − if (tmpSmp.origPek == NULL) | |
| 1345 | − { | |
| 1346 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1347 | − goto wavLoadError; | |
| 1348 | − } | |
| 1349 | − | |
| 1350 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1351 | − | |
| 1352 | − if (fread(tmpSmp.pek, sampleLength, 1, f) != 1) | |
| 1353 | − { | |
| 1354 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1355 | − goto wavLoadError; | |
| 1356 | − } | |
| 1357 | − | |
| 1358 | − audioDataU8 = (uint8_t *)tmpSmp.pek; | |
| 1359 | − | |
| 1360 | − // stereo conversion | |
| 1361 | − if (numChannels == 2) | |
| 1362 | − { | |
| 1363 | − sampleLength /= 2; | |
| 1364 | − switch (stereoSampleLoadMode) | |
| 1365 | − { | |
| 1366 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1367 | − { | |
| 1368 | − // remove right channel data | |
| 1369 | − for (i = 1; i < sampleLength; i++) | |
| 1370 | − audioDataU8[i] = audioDataU8[(i * 2) + 0]; | |
| 1371 | − } | |
| 1372 | − break; | |
| 1373 | − | |
| 1374 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1375 | − { | |
| 1376 | − // remove left channel data | |
| 1377 | − len32 = sampleLength - 1; | |
| 1378 | − for (i = 0; i < len32; i++) | |
| 1379 | − audioDataU8[i] = audioDataU8[(i * 2) + 1]; | |
| 1380 | − | |
| 1381 | − audioDataU8[i] = 128; | |
| 1382 | − } | |
| 1383 | − break; | |
| 1384 | − | |
| 1385 | − default: | |
| 1386 | − case STEREO_SAMPLE_CONVERT: | |
| 1387 | − { | |
| 1388 | − // mix stereo to mono | |
| 1389 | − len32 = sampleLength - 1; | |
| 1390 | − for (i = 0; i < len32; i++) | |
| 1391 | − audioDataU8[i] = (audioDataU8[(i * 2) + 0] + audioDataU8[(i * 2) + 1]) >> 1; | |
| 1392 | − | |
| 1393 | − audioDataU8[i] = 128; | |
| 1394 | − } | |
| 1395 | − break; | |
| 1396 | − } | |
| 1397 | − } | |
| 1398 | − | |
| 1399 | − // convert from unsigned to signed | |
| 1400 | − for (i = 0; i < sampleLength; i++) | |
| 1401 | − tmpSmp.pek[i] ^= 0x80; | |
| 1402 | − | |
| 1403 | − tmpSmp.typ &= ~16; // 8-bit | |
| 1404 | − } | |
| 1405 | − else if (bitsPerSample == 16) // 16-BIT INTEGER SAMPLE | |
| 1406 | − { | |
| 1407 | − sampleLength /= 2; | |
| 1408 | − | |
| 1409 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 2) + LOOP_FIX_LEN); | |
| 1410 | − if (tmpSmp.origPek == NULL) | |
| 1411 | − { | |
| 1412 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1413 | − goto wavLoadError; | |
| 1414 | − } | |
| 1415 | − | |
| 1416 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1417 | − | |
| 1418 | − if (fread(tmpSmp.pek, sampleLength, 2, f) != 2) | |
| 1419 | − { | |
| 1420 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1421 | − goto wavLoadError; | |
| 1422 | − } | |
| 1423 | − | |
| 1424 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 1425 | − | |
| 1426 | − // stereo conversion | |
| 1427 | − if (numChannels == 2) | |
| 1428 | − { | |
| 1429 | − sampleLength /= 2; | |
| 1430 | − | |
| 1431 | − switch (stereoSampleLoadMode) | |
| 1432 | − { | |
| 1433 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1434 | − { | |
| 1435 | − // remove right channel data | |
| 1436 | − for (i = 1; i < sampleLength; i++) | |
| 1437 | − audioDataS16[i] = audioDataS16[(i * 2) + 0]; | |
| 1438 | − } | |
| 1439 | − break; | |
| 1440 | − | |
| 1441 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1442 | − { | |
| 1443 | − // remove left channel data | |
| 1444 | − len32 = sampleLength - 1; | |
| 1445 | − for (i = 0; i < len32; i++) | |
| 1446 | − audioDataS16[i] = audioDataS16[(i * 2) + 1]; | |
| 1447 | − | |
| 1448 | − audioDataS16[i] = 0; | |
| 1449 | − } | |
| 1450 | − break; | |
| 1451 | − | |
| 1452 | − default: | |
| 1453 | − case STEREO_SAMPLE_CONVERT: | |
| 1454 | − { | |
| 1455 | − // mix stereo to mono | |
| 1456 | − len32 = sampleLength - 1; | |
| 1457 | − for (i = 0; i < len32; i++) | |
| 1458 | − { | |
| 1459 | − smp32 = audioDataS16[(i * 2) + 0] + audioDataS16[(i * 2) + 1]; | |
| 1460 | − audioDataS16[i] = (int16_t)(smp32 >> 1); | |
| 1461 | − } | |
| 1462 | − | |
| 1463 | − audioDataS16[i] = 0; | |
| 1464 | − } | |
| 1465 | − break; | |
| 1466 | − } | |
| 1467 | − } | |
| 1468 | − | |
| 1469 | − sampleLength *= 2; | |
| 1470 | − tmpSmp.typ |= 16; // 16-bit | |
| 1471 | − } | |
| 1472 | − else if (bitsPerSample == 24) // 24-BIT INTEGER SAMPLE | |
| 1473 | − { | |
| 1474 | − sampleLength /= 3; | |
| 1475 | − | |
| 1476 | − tmpSmp.origPek = (int8_t *)malloc(((sampleLength * 4) * 2) + LOOP_FIX_LEN); | |
| 1477 | − if (tmpSmp.origPek == NULL) | |
| 1478 | − { | |
| 1479 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1480 | − goto wavLoadError; | |
| 1481 | − } | |
| 1482 | − | |
| 1483 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1484 | − | |
| 1485 | − if (fread(&tmpSmp.pek[sampleLength], sampleLength, 3, f) != 3) | |
| 1486 | − { | |
| 1487 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1488 | − goto wavLoadError; | |
| 1489 | − } | |
| 1490 | − | |
| 1491 | − audioDataS32 = (int32_t *)tmpSmp.pek; | |
| 1492 | − | |
| 1493 | − // convert to 32-bit | |
| 1494 | − audioDataU8 = (uint8_t *)tmpSmp.pek + sampleLength; | |
| 1495 | − for (i = 0; i < sampleLength; i++) | |
| 1496 | − { | |
| 1497 | − audioDataS32[i] = (audioDataU8[2] << 24) | (audioDataU8[1] << 16) | (audioDataU8[0] << 8); | |
| 1498 | − audioDataU8 += 3; | |
| 1499 | − } | |
| 1500 | − | |
| 1501 | − // stereo conversion | |
| 1502 | − if (numChannels == 2) | |
| 1503 | − { | |
| 1504 | − sampleLength /= 2; | |
| 1505 | − switch (stereoSampleLoadMode) | |
| 1506 | − { | |
| 1507 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1508 | − { | |
| 1509 | − // remove right channel data | |
| 1510 | − for (i = 1; i < sampleLength; i++) | |
| 1511 | − audioDataS32[i] = audioDataS32[(i * 2) + 0]; | |
| 1512 | − } | |
| 1513 | − break; | |
| 1514 | − | |
| 1515 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1516 | − { | |
| 1517 | − // remove left channel data | |
| 1518 | − len32 = sampleLength - 1; | |
| 1519 | − for (i = 0; i < len32; i++) | |
| 1520 | − audioDataS32[i] = audioDataS32[(i * 2) + 1]; | |
| 1521 | − | |
| 1522 | − audioDataS32[i] = 0; | |
| 1523 | − } | |
| 1524 | − break; | |
| 1525 | − | |
| 1526 | − default: | |
| 1527 | − case STEREO_SAMPLE_CONVERT: | |
| 1528 | − { | |
| 1529 | − // mix stereo to mono | |
| 1530 | − len32 = sampleLength - 1; | |
| 1531 | − for (i = 0; i < len32; i++) | |
| 1532 | − { | |
| 1533 | − smp64 = audioDataS32[(i * 2) + 0]; | |
| 1534 | − smp64 += audioDataS32[(i * 2) + 1]; | |
| 1535 | − smp64 >>= 1; | |
| 1536 | − | |
| 1537 | − audioDataS32[i] = (int32_t)smp64; | |
| 1538 | − } | |
| 1539 | − | |
| 1540 | − audioDataS32[i] = 0; | |
| 1541 | − } | |
| 1542 | − break; | |
| 1543 | − } | |
| 1544 | − } | |
| 1545 | − | |
| 1546 | − normalize32bitSigned(audioDataS32, sampleLength); | |
| 1547 | − | |
| 1548 | − // downscale to 16-bit (ultra fast method!) | |
| 1549 | − | |
| 1550 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 1551 | − audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; | |
| 1552 | − | |
| 1553 | − for (i = 0; i < sampleLength; i++) | |
| 1554 | − { | |
| 1555 | − audioDataS16[i] = audioDataS16_2[i]; | |
| 1556 | − audioDataS16_2++; | |
| 1557 | − } | |
| 1558 | − | |
| 1559 | − sampleLength *= 2; | |
| 1560 | − tmpSmp.typ |= 16; // 16-bit | |
| 1561 | − } | |
| 1562 | − else if (audioFormat == WAV_FORMAT_PCM && bitsPerSample == 32) // 32-BIT INTEGER SAMPLE | |
| 1563 | − { | |
| 1564 | − sampleLength /= 4; | |
| 1565 | − | |
| 1566 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 4) + LOOP_FIX_LEN); | |
| 1567 | − if (tmpSmp.origPek == NULL) | |
| 1568 | − { | |
| 1569 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1570 | − goto wavLoadError; | |
| 1571 | − } | |
| 1572 | − | |
| 1573 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1574 | − | |
| 1575 | − if (fread(tmpSmp.pek, sampleLength, 4, f) != 4) | |
| 1576 | − { | |
| 1577 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1578 | − goto wavLoadError; | |
| 1579 | − } | |
| 1580 | − | |
| 1581 | − audioDataS32 = (int32_t *)tmpSmp.pek; | |
| 1582 | − | |
| 1583 | − // stereo conversion | |
| 1584 | − if (numChannels == 2) | |
| 1585 | − { | |
| 1586 | − sampleLength /= 2; | |
| 1587 | − switch (stereoSampleLoadMode) | |
| 1588 | − { | |
| 1589 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1590 | − { | |
| 1591 | − // remove right channel data | |
| 1592 | − for (i = 1; i < sampleLength; i++) | |
| 1593 | − audioDataS32[i] = audioDataS32[(i * 2) + 0]; | |
| 1594 | − } | |
| 1595 | − break; | |
| 1596 | − | |
| 1597 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1598 | − { | |
| 1599 | − // remove left channel data | |
| 1600 | − len32 = sampleLength - 1; | |
| 1601 | − for (i = 0; i < len32; i++) | |
| 1602 | − audioDataS32[i] = audioDataS32[(i * 2) + 1]; | |
| 1603 | − | |
| 1604 | − audioDataS32[i] = 0; | |
| 1605 | − } | |
| 1606 | − break; | |
| 1607 | − | |
| 1608 | − default: | |
| 1609 | − case STEREO_SAMPLE_CONVERT: | |
| 1610 | − { | |
| 1611 | − // mix stereo to mono | |
| 1612 | − len32 = sampleLength - 1; | |
| 1613 | − for (i = 0; i < len32; i++) | |
| 1614 | − { | |
| 1615 | − smp64 = audioDataS32[(i * 2) + 0]; | |
| 1616 | − smp64 += audioDataS32[(i * 2) + 1]; | |
| 1617 | − smp64 >>= 1; | |
| 1618 | − | |
| 1619 | − audioDataS32[i] = (int32_t)smp64; | |
| 1620 | − } | |
| 1621 | − | |
| 1622 | − audioDataS32[i] = 0; | |
| 1623 | − } | |
| 1624 | − break; | |
| 1625 | − } | |
| 1626 | − } | |
| 1627 | − | |
| 1628 | − normalize32bitSigned(audioDataS32, sampleLength); | |
| 1629 | − | |
| 1630 | − // downscale to 16-bit (ultra fast method!) | |
| 1631 | − | |
| 1632 | − audioDataS16 = (int16_t *)tmpSmp.pek; | |
| 1633 | − audioDataS16_2 = (int16_t *)tmpSmp.pek + 1; | |
| 1634 | − | |
| 1635 | − for (i = 0; i < sampleLength; i++) | |
| 1636 | − { | |
| 1637 | − audioDataS16[i] = audioDataS16_2[i]; | |
| 1638 | − audioDataS16_2++; | |
| 1639 | − } | |
| 1640 | − | |
| 1641 | − sampleLength *= 2; | |
| 1642 | − tmpSmp.typ |= 16; // 16-bit | |
| 1643 | − } | |
| 1644 | − else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 32) // 32-BIT FLOATING POINT SAMPLE | |
| 1645 | − { | |
| 1646 | − sampleLength /= 4; | |
| 26 | + FORMAT_UNKNOWN = 0, | |
| 27 | + FORMAT_IFF = 1, | |
| 28 | + FORMAT_WAV = 2, | |
| 29 | + FORMAT_AIFF = 3 | |
| 30 | +}; | |
| 1647 | 31 | |
| 1648 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 4) + LOOP_FIX_LEN); | |
| 1649 | − if (tmpSmp.origPek == NULL) | |
| 1650 | − { | |
| 1651 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1652 | − goto wavLoadError; | |
| 1653 | − } | |
| 32 | +// file extensions accepted by Disk Op. in sample mode | |
| 33 | +char *supportedSmpExtensions[] = | |
| 34 | +{ | |
| 35 | + "iff", "raw", "wav", "snd", "smp", "sam", "aif", "pat", "aiff", | |
| 1654 | 36 | |
| 1655 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 37 | + "END_OF_LIST" // do NOT move, remove or edit this line! | |
| 38 | +}; | |
| 1656 | 39 | |
| 1657 | − if (fread(tmpSmp.pek, sampleLength, 4, f) != 4) | |
| 1658 | − { | |
| 1659 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1660 | − goto wavLoadError; | |
| 1661 | − } | |
| 40 | +// globals for sample loaders | |
| 41 | +bool loadAsInstrFlag, smpFilenameSet; | |
| 42 | +char *smpFilename; | |
| 43 | +uint8_t sampleSlot; | |
| 44 | +sampleTyp tmpSmp; | |
| 45 | +// -------------------------- | |
| 1662 | 46 | |
| 1663 | − fAudioDataFloat = (float *)tmpSmp.pek; | |
| 47 | +static volatile bool sampleIsLoading; | |
| 48 | +static SDL_Thread *thread; | |
| 1664 | 49 | |
| 1665 | − // stereo conversion | |
| 1666 | − if (numChannels == 2) | |
| 1667 | − { | |
| 1668 | − sampleLength /= 2; | |
| 1669 | − switch (stereoSampleLoadMode) | |
| 1670 | − { | |
| 1671 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1672 | − { | |
| 1673 | − // remove right channel data | |
| 1674 | − for (i = 1; i < sampleLength; i++) | |
| 1675 | − fAudioDataFloat[i] = fAudioDataFloat[(i * 2) + 0]; | |
| 1676 | − } | |
| 1677 | − break; | |
| 50 | +static void freeTmpSample(sampleTyp *s); | |
| 1678 | 51 | |
| 1679 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1680 | − { | |
| 1681 | − // remove left channel data | |
| 1682 | − len32 = sampleLength - 1; | |
| 1683 | − for (i = 0; i < len32; i++) | |
| 1684 | − fAudioDataFloat[i] = fAudioDataFloat[(i * 2) + 1]; | |
| 52 | +// Crude sample detection routine. These aren't always accurate detections! | |
| 53 | +static int8_t detectSample(FILE *f) | |
| 54 | +{ | |
| 55 | + uint8_t D[256]; | |
| 1685 | 56 | |
| 1686 | − fAudioDataFloat[i] = 0.0f; | |
| 1687 | − } | |
| 1688 | − break; | |
| 57 | + uint32_t oldPos = ftell(f); | |
| 58 | + rewind(f); | |
| 59 | + memset(D, 0, sizeof (D)); | |
| 60 | + fread(D, 1, sizeof (D), f); | |
| 61 | + fseek(f, oldPos, SEEK_SET); | |
| 1689 | 62 | |
| 1690 | − default: | |
| 1691 | − case STEREO_SAMPLE_CONVERT: | |
| 1692 | − { | |
| 1693 | − // mix stereo to mono | |
| 1694 | − len32 = sampleLength - 1; | |
| 1695 | − for (i = 0; i < len32; i++) | |
| 1696 | − fAudioDataFloat[i] = (fAudioDataFloat[(i * 2) + 0] + fAudioDataFloat[(i * 2) + 1]) * 0.5f; | |
| 63 | + if (!memcmp("FORM", &D[0], 4) && (!memcmp("8SVX", &D[8], 4) || !memcmp("16SV", &D[8], 4))) | |
| 64 | + return FORMAT_IFF; | |
| 1697 | 65 | |
| 1698 | − fAudioDataFloat[i] = 0.0f; | |
| 1699 | − } | |
| 1700 | − break; | |
| 1701 | − } | |
| 1702 | − } | |
| 66 | + if (!memcmp("RIFF", &D[0], 4) && !memcmp("WAVE", &D[8], 4)) | |
| 67 | + return FORMAT_WAV; | |
| 1703 | 68 | |
| 1704 | − normalize16bitFloatSigned(fAudioDataFloat, sampleLength); | |
| 69 | + if (!memcmp("FORM", &D[0], 4) && (!memcmp("AIFF", &D[8], 4) || !memcmp("AIFC", &D[8], 4))) | |
| 70 | + return FORMAT_AIFF; | |
| 1705 | 71 | |
| 1706 | − ptr16 = (int16_t *)tmpSmp.pek; | |
| 1707 | − for (i = 0; i < sampleLength; i++) | |
| 1708 | − ptr16[i] = (int16_t)fAudioDataFloat[i]; // should use SIMD if available | |
| 72 | + return FORMAT_UNKNOWN; | |
| 73 | +} | |
| 1709 | 74 | |
| 1710 | − sampleLength *= 2; | |
| 1711 | − tmpSmp.typ |= 16; // 16-bit | |
| 1712 | − } | |
| 1713 | − else if (audioFormat == WAV_FORMAT_IEEE_FLOAT && bitsPerSample == 64) // 64-BIT FLOATING POINT SAMPLE | |
| 75 | +static int32_t SDLCALL loadSampleThread(void *ptr) | |
| 76 | +{ | |
| 77 | + if (editor.tmpFilenameU == NULL) | |
| 1714 | 78 | { |
| 1715 | − sampleLength /= 8; | |
| 1716 | − | |
| 1717 | − tmpSmp.origPek = (int8_t *)malloc((sampleLength * 8) + LOOP_FIX_LEN); | |
| 1718 | − if (tmpSmp.origPek == NULL) | |
| 1719 | − { | |
| 1720 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1721 | − goto wavLoadError; | |
| 1722 | − } | |
| 1723 | − | |
| 1724 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 1725 | − | |
| 1726 | − if (fread(tmpSmp.pek, sampleLength, 8, f) != 8) | |
| 1727 | − { | |
| 1728 | − okBoxThreadSafe(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1729 | − goto wavLoadError; | |
| 1730 | − } | |
| 1731 | − | |
| 1732 | − dAudioDataDouble = (double *)tmpSmp.pek; | |
| 1733 | − | |
| 1734 | − // stereo conversion | |
| 1735 | − if (numChannels == 2) | |
| 1736 | − { | |
| 1737 | − sampleLength /= 2; | |
| 1738 | − switch (stereoSampleLoadMode) | |
| 1739 | − { | |
| 1740 | − case STEREO_SAMPLE_READ_LEFT: | |
| 1741 | − { | |
| 1742 | − // remove right channel data | |
| 1743 | − for (i = 1; i < sampleLength; i++) | |
| 1744 | − dAudioDataDouble[i] = dAudioDataDouble[(i * 2) + 0]; | |
| 1745 | − } | |
| 1746 | − break; | |
| 1747 | − | |
| 1748 | − case STEREO_SAMPLE_READ_RIGHT: | |
| 1749 | − { | |
| 1750 | − // remove left channel data | |
| 1751 | − len32 = sampleLength - 1; | |
| 1752 | − for (i = 0; i < len32; i++) | |
| 1753 | − dAudioDataDouble[i] = dAudioDataDouble[(i * 2) + 1]; | |
| 1754 | − | |
| 1755 | − dAudioDataDouble[i] = 0.0; | |
| 1756 | − } | |
| 1757 | − break; | |
| 1758 | − | |
| 1759 | − default: | |
| 1760 | − case STEREO_SAMPLE_CONVERT: | |
| 1761 | − { | |
| 1762 | − // mix stereo to mono | |
| 1763 | − len32 = sampleLength - 1; | |
| 1764 | − for (i = 0; i < len32; i++) | |
| 1765 | − dAudioDataDouble[i] = (dAudioDataDouble[(i * 2) + 0] + dAudioDataDouble[(i * 2) + 1]) * 0.5; | |
| 1766 | − | |
| 1767 | − dAudioDataDouble[i] = 0.0; | |
| 1768 | − } | |
| 1769 | − break; | |
| 1770 | − } | |
| 1771 | − } | |
| 1772 | − | |
| 1773 | − normalize64bitDoubleSigned(dAudioDataDouble, sampleLength); | |
| 1774 | − | |
| 1775 | − ptr16 = (int16_t *)tmpSmp.pek; | |
| 1776 | − for (i = 0; i < sampleLength; i++) | |
| 1777 | − ptr16[i] = (int16_t)dAudioDataDouble[i]; // should use SIMD if available | |
| 1778 | − | |
| 1779 | − sampleLength *= 2; | |
| 1780 | − tmpSmp.typ |= 16; // 16-bit | |
| 79 | + loaderMsgBox("General I/O error during loading!"); | |
| 80 | + return false; | |
| 1781 | 81 | } |
| 1782 | 82 | |
| 1783 | − // adjust memory needed | |
| 1784 | − newPtr = (int8_t *)realloc(tmpSmp.origPek, sampleLength + LOOP_FIX_LEN); | |
| 1785 | − if (newPtr != NULL) | |
| 83 | + FILE *f = UNICHAR_FOPEN(editor.tmpFilenameU, "rb"); | |
| 84 | + if (f == NULL) | |
| 1786 | 85 | { |
| 1787 | − tmpSmp.origPek = newPtr; | |
| 1788 | − tmpSmp.pek = tmpSmp.origPek + SMP_DAT_OFFSET; | |
| 86 | + loaderMsgBox("General I/O error during loading! Is the file in use?"); | |
| 87 | + return false; | |
| 1789 | 88 | } |
| 1790 | 89 | |
| 1791 | − tuneSample(&tmpSmp, sampleRate, audio.linearPeriodsFlag); | |
| 1792 | − | |
| 1793 | − tmpSmp.vol = 64; | |
| 1794 | − tmpSmp.pan = 128; | |
| 1795 | − tmpSmp.len = sampleLength; | |
| 90 | + int8_t format = detectSample(f); | |
| 91 | + fseek(f, 0, SEEK_END); | |
| 92 | + uint32_t filesize = ftell(f); | |
| 1796 | 93 | |
| 1797 | − // ---- READ "smpl" chunk ---- | |
| 1798 | − if (smplPtr != 0 && smplLen > 52) | |
| 94 | + if (filesize == 0) | |
| 1799 | 95 | { |
| 1800 | − fseek(f, smplPtr + 28, SEEK_SET); // seek to first wanted byte | |
| 1801 | − | |
| 1802 | − fread(&numLoops, 4, 1, f); | |
| 1803 | − if (numLoops == 1) | |
| 1804 | − { | |
| 1805 | − fseek(f, 4 + 4, SEEK_CUR); // skip "samplerData" and "identifier" | |
| 1806 | − | |
| 1807 | − fread(&loopType, 4, 1, f); | |
| 1808 | − fread(&loopStart, 4, 1, f); | |
| 1809 | − fread(&loopEnd, 4, 1, f); | |
| 1810 | − | |
| 1811 | − loopEnd++; | |
| 1812 | − | |
| 1813 | − if (tmpSmp.typ & 16) | |
| 1814 | − { | |
| 1815 | − loopStart *= 2; | |
| 1816 | − loopEnd *= 2; | |
| 1817 | − } | |
| 1818 | − | |
| 1819 | − if (loopEnd <= sampleLength) | |
| 1820 | − { | |
| 1821 | − tmpSmp.repS = loopStart; | |
| 1822 | − tmpSmp.repL = loopEnd - loopStart; | |
| 1823 | − tmpSmp.typ |= ((loopType == 0) ? 1 : 2); | |
| 1824 | − } | |
| 1825 | − } | |
| 96 | + fclose(f); | |
| 97 | + loaderMsgBox("Error loading sample: The file is empty!"); | |
| 98 | + return false; | |
| 1826 | 99 | } |
| 1827 | − // --------------------------- | |
| 1828 | − | |
| 1829 | − // ---- READ "xtra" chunk ---- | |
| 1830 | − if (xtraPtr != 0 && xtraLen >= 8) | |
| 1831 | − { | |
| 1832 | − fseek(f, xtraPtr, SEEK_SET); | |
| 1833 | − | |
| 1834 | − fread(&xtraFlags, 4, 1, f); // flags | |
| 1835 | 100 | |
| 1836 | − // panning (0..256) | |
| 1837 | − if (xtraFlags & 0x20) // set panning flag | |
| 1838 | − { | |
| 1839 | − fread(&tempPan, 2, 1, f); | |
| 1840 | − if (tempPan > 255) | |
| 1841 | − tempPan = 255; | |
| 1842 | − | |
| 1843 | − tmpSmp.pan = (uint8_t)tempPan; | |
| 1844 | − } | |
| 1845 | − else | |
| 1846 | − { | |
| 1847 | − // don't read panning, skip it | |
| 1848 | − fseek(f, 2, SEEK_CUR); | |
| 1849 | − } | |
| 1850 | − | |
| 1851 | − // volume (0..256) | |
| 1852 | − fread(&tempVol, 2, 1, f); | |
| 1853 | − if (tempVol > 256) | |
| 1854 | − tempVol = 256; | |
| 1855 | − | |
| 1856 | − tmpSmp.vol = (uint8_t)(tempVol / 4); // 0..256 -> 0..64 | |
| 1857 | − } | |
| 1858 | − // --------------------------- | |
| 101 | + bool sampleLoaded = false; | |
| 1859 | 102 | |
| 1860 | − // ---- READ "INAM" chunk ---- | |
| 1861 | − if (inamPtr != 0 && inamLen > 0) | |
| 103 | + rewind(f); | |
| 104 | + switch (format) | |
| 1862 | 105 | { |
| 1863 | − fseek(f, inamPtr, SEEK_SET); | |
| 106 | + case FORMAT_IFF: sampleLoaded = loadIFF(f, filesize); break; | |
| 107 | + case FORMAT_WAV: sampleLoaded = loadWAV(f, filesize); break; | |
| 108 | + case FORMAT_AIFF: sampleLoaded = loadAIFF(f, filesize); break; | |
| 109 | + default: sampleLoaded = loadRAW(f, filesize); break; | |
| 110 | + } | |
| 111 | + fclose(f); | |
| 1864 | 112 | |
| 1865 | − memset(tmpSmp.name, 0, sizeof (tmpSmp.name)); | |
| 1866 | − for (i = 0; i < 22; i++) | |
| 1867 | − { | |
| 1868 | − if (i < inamLen) | |
| 1869 | − { | |
| 1870 | − chr = (char)fgetc(f); | |
| 1871 | − if (chr == '\0') | |
| 1872 | − break; | |
| 113 | + if (!sampleLoaded) | |
| 114 | + goto loadError; | |
| 1873 | 115 | |
| 1874 | − tmpSmp.name[i] = chr; | |
| 1875 | − } | |
| 1876 | − } | |
| 1877 | − } | |
| 1878 | − else | |
| 116 | + // sample loaded successfully! | |
| 117 | + | |
| 118 | + if (!smpFilenameSet) // if we didn't set a custom sample name in the loader, set it to its filename | |
| 1879 | 119 | { |
| 1880 | − // set sample name from filename if we didn't load name from .wav | |
| 1881 | − tmpFilename = unicharToCp437(filename, true); | |
| 120 | + char *tmpFilename = unicharToCp437(editor.tmpFilenameU, true); | |
| 1882 | 121 | if (tmpFilename != NULL) |
| 1883 | 122 | { |
| 1884 | − j = (int32_t)strlen(tmpFilename); | |
| 1885 | − while (j--) | |
| 123 | + int32_t i = (int32_t)strlen(tmpFilename); | |
| 124 | + while (i--) | |
| 1886 | 125 | { |
| 1887 | − if (tmpFilename[j] == DIR_DELIMITER) | |
| 126 | + if (tmpFilename[i] == DIR_DELIMITER) | |
| 1888 | 127 | break; |
| 1889 | 128 | } |
| 1890 | 129 | |
| 1891 | − tmpPtr = tmpFilename; | |
| 1892 | − if (j > 0) | |
| 1893 | − tmpPtr += j + 1; | |
| 130 | + char *tmpPtr = tmpFilename; | |
| 131 | + if (i > 0) | |
| 132 | + tmpPtr += i+1; | |
| 1894 | 133 | |
| 1895 | 134 | sanitizeFilename(tmpPtr); |
| 1896 | 135 | |
| 1897 | − filenameLen = (uint32_t)strlen(tmpPtr); | |
| 136 | + int32_t filenameLen = (int32_t)strlen(tmpPtr); | |
| 1898 | 137 | for (i = 0; i < 22; i++) |
| 1899 | 138 | { |
| 1900 | 139 | if (i < filenameLen) |
| @@ -1907,7 +146,7 @@ static int32_t SDLCALL loadWAVSample(void *ptr) · 6 unmodified lines | ||
| 1907 | 146 | } |
| 1908 | 147 | } |
| 1909 | 148 | |
| 1910 | − fclose(f); | |
| 149 | + fixString(tmpSmp.name, 21); // remove leading spaces from sample filename | |
| 1911 | 150 | |
| 1912 | 151 | lockMixerCallback(); |
| 1913 | 152 | if (loadAsInstrFlag) // if loaded in instrument mode |
| @@ -1919,172 +158,82 @@ static int32_t SDLCALL loadWAVSample(void *ptr) · 5 unmodified lines | ||
| 1919 | 158 | if (instr[editor.curInstr] == NULL) |
| 1920 | 159 | allocateInstr(editor.curInstr); |
| 1921 | 160 | |
| 1922 | − if (instr[editor.curInstr] != NULL) | |
| 1923 | − { | |
| 1924 | − s = &instr[editor.curInstr]->samp[sampleSlot]; | |
| 1925 | − | |
| 1926 | − freeSample(editor.curInstr, sampleSlot); | |
| 1927 | − memcpy(s, &tmpSmp, sizeof (sampleTyp)); | |
| 1928 | − fixSample(s); | |
| 1929 | − } | |
| 1930 | − else | |
| 161 | + if (instr[editor.curInstr] == NULL) | |
| 1931 | 162 | { |
| 1932 | − okBoxThreadSafe(0, "System message", "Not enough memory!"); | |
| 1933 | − goto wavLoadError; | |
| 163 | + loaderMsgBox("Not enough memory!"); | |
| 164 | + goto loadError; | |
| 1934 | 165 | } |
| 166 | + | |
| 167 | + sampleTyp *s = &instr[editor.curInstr]->samp[sampleSlot]; | |
| 168 | + | |
| 169 | + freeSample(editor.curInstr, sampleSlot); | |
| 170 | + memcpy(s, &tmpSmp, sizeof (sampleTyp)); | |
| 171 | + fixSample(s); // prepares sample for branchless resampling interpolation | |
| 172 | + fixInstrAndSampleNames(editor.curInstr); | |
| 173 | + | |
| 1935 | 174 | unlockMixerCallback(); |
| 1936 | 175 | |
| 1937 | − fixSampleName(editor.curInstr); | |
| 1938 | 176 | setSongModifiedFlag(); |
| 1939 | − stereoSampleLoadMode = -1; | |
| 1940 | 177 | |
| 1941 | − // also sets mouse busy to false when done | |
| 178 | + // when caught in main/video thread, it disables busy mouse and sets sampleIsLoading to true | |
| 1942 | 179 | editor.updateCurSmp = true; |
| 1943 | 180 | |
| 1944 | 181 | return true; |
| 1945 | 182 | |
| 1946 | −wavLoadError: | |
| 1947 | − if (f != NULL) fclose(f); | |
| 1948 | − if (tmpSmp.origPek != NULL) free(tmpSmp.origPek); | |
| 1949 | − | |
| 1950 | − stereoSampleLoadMode = -1; | |
| 183 | +loadError: | |
| 184 | + setMouseBusy(false); | |
| 185 | + freeTmpSample(&tmpSmp); | |
| 1951 | 186 | sampleIsLoading = false; |
| 1952 | − | |
| 1953 | 187 | return false; |
| 1954 | 188 | |
| 1955 | 189 | (void)ptr; |
| 1956 | 190 | } |
| 1957 | 191 | |
| 1958 | −bool loadSample(UNICHAR *filenameU, uint8_t smpNr, bool instrFlag) | |
| 192 | +static void freeTmpSample(sampleTyp *s) | |
| 1959 | 193 | { |
| 1960 | − char tmpBuffer[16+1]; | |
| 1961 | − | |
| 1962 | − if (sampleIsLoading) | |
| 1963 | − return false; | |
| 1964 | − | |
| 1965 | − stereoSampleLoadMode = 0; | |
| 1966 | − | |
| 1967 | − sampleSlot = smpNr; | |
| 1968 | − loadAsInstrFlag = instrFlag; | |
| 1969 | − | |
| 1970 | − if (editor.curInstr == 0) | |
| 1971 | − { | |
| 1972 | − okBox(0, "System message", "The zero-instrument cannot hold intrument data."); | |
| 1973 | − return false; | |
| 1974 | − } | |
| 1975 | − | |
| 1976 | − FILE *f = UNICHAR_FOPEN(filenameU, "rb"); | |
| 1977 | − if (f == NULL) | |
| 194 | + if (s->origPek != NULL) | |
| 1978 | 195 | { |
| 1979 | − okBox(0, "System message", "General I/O error during loading! Is the file in use?"); | |
| 1980 | − return false; | |
| 196 | + free(s->origPek); | |
| 197 | + s->origPek = NULL; | |
| 1981 | 198 | } |
| 1982 | 199 | |
| 1983 | − memset(tmpBuffer, 0, sizeof (tmpBuffer)); | |
| 1984 | − if (fread(tmpBuffer, sizeof (tmpBuffer) - 1, 1, f) == 1) | |
| 1985 | − { | |
| 1986 | − tmpBuffer[sizeof (tmpBuffer) - 1] = '\0'; | |
| 1987 | − | |
| 1988 | − // detect what sample format this is... | |
| 1989 | − | |
| 1990 | − // WAV | |
| 1991 | − if (!strncmp("RIFF", tmpBuffer, 4) && !strncmp("WAVE", tmpBuffer + 8, 4)) | |
| 1992 | − { | |
| 1993 | − // let the user pick what to do with stereo samples... | |
| 1994 | − if (wavIsStereo(f)) | |
| 1995 | − stereoSampleLoadMode = okBox(5, "System request", "This is a stereo sample..."); | |
| 1996 | − | |
| 1997 | − sampleIsLoading = true; | |
| 1998 | − | |
| 1999 | − fclose(f); | |
| 2000 | − UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); | |
| 2001 | − | |
| 2002 | − mouseAnimOn(); | |
| 2003 | − thread = SDL_CreateThread(loadWAVSample, NULL, NULL); | |
| 2004 | − if (thread == NULL) | |
| 2005 | − { | |
| 2006 | − okBox(0, "System message", "Couldn't create thread!"); | |
| 2007 | − sampleIsLoading = false; | |
| 2008 | − return false; | |
| 2009 | − } | |
| 2010 | − | |
| 2011 | − SDL_DetachThread(thread); | |
| 2012 | − return true; | |
| 2013 | − } | |
| 2014 | − | |
| 2015 | − // AIFF or IFF | |
| 2016 | − if (!strncmp("FORM", tmpBuffer, 4)) | |
| 2017 | − { | |
| 2018 | − if (!strncmp("AIFC", tmpBuffer + 8, 4)) | |
| 2019 | − { | |
| 2020 | − // AIFC (not supported) | |
| 2021 | − | |
| 2022 | − fclose(f); | |
| 2023 | − okBox(0, "System message", "Error loading sample: This AIFF type (AIFC) is not supported!"); | |
| 2024 | − return true; | |
| 2025 | − } | |
| 2026 | − else if (!strncmp("AIFF", tmpBuffer + 8, 4)) | |
| 2027 | − { | |
| 2028 | − // AIFF | |
| 2029 | − | |
| 2030 | − // let the user pick what to do with stereo samples... | |
| 2031 | − if (aiffIsStereo(f)) | |
| 2032 | − stereoSampleLoadMode = okBox(5, "System request", "This is a stereo sample..."); | |
| 2033 | − | |
| 2034 | − sampleIsLoading = true; | |
| 2035 | − | |
| 2036 | − fclose(f); | |
| 2037 | − UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); | |
| 2038 | − | |
| 2039 | − mouseAnimOn(); | |
| 2040 | − thread = SDL_CreateThread(loadAIFFSample, NULL, NULL); | |
| 2041 | − if (thread == NULL) | |
| 2042 | − { | |
| 2043 | − okBox(0, "System message", "Couldn't create thread!"); | |
| 2044 | − sampleIsLoading = false; | |
| 2045 | − return false; | |
| 2046 | − } | |
| 2047 | − | |
| 2048 | − SDL_DetachThread(thread); | |
| 2049 | − return true; | |
| 2050 | − } | |
| 2051 | − else if (!strncmp("8SVX", tmpBuffer + 8, 4) || !strncmp("16SV", tmpBuffer + 8, 4)) | |
| 2052 | − { | |
| 2053 | − // IFF | |
| 200 | + s->pek = NULL; | |
| 201 | +} | |
| 2054 | 202 | |
| 2055 | − sampleIsLoading = true; | |
| 203 | +void removeSampleIsLoadingFlag(void) | |
| 204 | +{ | |
| 205 | + sampleIsLoading = false; | |
| 206 | +} | |
| 2056 | 207 | |
| 2057 | − fclose(f); | |
| 2058 | − UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); | |
| 208 | +bool loadSample(UNICHAR *filenameU, uint8_t smpNr, bool instrFlag) | |
| 209 | +{ | |
| 210 | + if (sampleIsLoading || filenameU == NULL) | |
| 211 | + return false; | |
| 2059 | 212 | |
| 2060 | − mouseAnimOn(); | |
| 2061 | − thread = SDL_CreateThread(loadIFFSample, NULL, NULL); | |
| 2062 | − if (thread == NULL) | |
| 2063 | − { | |
| 2064 | − okBox(0, "System message", "Couldn't create thread!"); | |
| 2065 | − sampleIsLoading = false; | |
| 2066 | − return false; | |
| 2067 | − } | |
| 213 | + // setup message box functions | |
| 214 | + loaderMsgBox = myLoaderMsgBoxThreadSafe; | |
| 215 | + loaderSysReq = okBoxThreadSafe; | |
| 2068 | 216 | |
| 2069 | − SDL_DetachThread(thread); | |
| 2070 | − return true; | |
| 2071 | − } | |
| 2072 | − } | |
| 217 | + if (editor.curInstr == 0) | |
| 218 | + { | |
| 219 | + loaderMsgBox("The zero-instrument cannot hold intrument data."); | |
| 220 | + return false; | |
| 2073 | 221 | } |
| 2074 | 222 | |
| 2075 | − // load as RAW sample | |
| 2076 | − | |
| 223 | + sampleSlot = smpNr; | |
| 224 | + loadAsInstrFlag = instrFlag; | |
| 2077 | 225 | sampleIsLoading = true; |
| 226 | + smpFilenameSet = false; | |
| 2078 | 227 | |
| 2079 | − fclose(f); | |
| 228 | + memset(&tmpSmp, 0, sizeof (tmpSmp)); | |
| 2080 | 229 | UNICHAR_STRCPY(editor.tmpFilenameU, filenameU); |
| 2081 | 230 | |
| 2082 | 231 | mouseAnimOn(); |
| 2083 | − thread = SDL_CreateThread(loadRawSample, NULL, NULL); | |
| 232 | + thread = SDL_CreateThread(loadSampleThread, NULL, NULL); | |
| 2084 | 233 | if (thread == NULL) |
| 2085 | 234 | { |
| 2086 | − okBox(0, "System message", "Couldn't create thread!"); | |
| 2087 | 235 | sampleIsLoading = false; |
| 236 | + loaderMsgBox("Couldn't create thread!"); | |
| 2088 | 237 | return false; |
| 2089 | 238 | } |
| 2090 | 239 | |
| @@ -2092,7 +241,7 @@ bool loadSample(UNICHAR *filenameU, uint8_t smpNr, bool instrFlag) · 1 unmodified line | ||
| 2092 | 241 | return true; |
| 2093 | 242 | } |
| 2094 | 243 | |
| 2095 | −static void normalize32bitSigned(int32_t *sampleData, uint32_t sampleLength) | |
| 244 | +void normalizeSigned32Bit(int32_t *sampleData, uint32_t sampleLength) | |
| 2096 | 245 | { |
| 2097 | 246 | uint32_t i; |
| 2098 | 247 | |
| @@ -2112,7 +261,7 @@ static void normalize32bitSigned(int32_t *sampleData, uint32_t sampleLength) · 13 unmodified lines | ||
| 2112 | 261 | sampleData[i] = (int32_t)(sampleData[i] * dGain); |
| 2113 | 262 | } |
| 2114 | 263 | |
| 2115 | −static void normalize16bitFloatSigned(float *fSampleData, uint32_t sampleLength) | |
| 264 | +void normalize32BitFloatToSigned16Bit(float *fSampleData, uint32_t sampleLength) | |
| 2116 | 265 | { |
| 2117 | 266 | uint32_t i; |
| 2118 | 267 | |
| @@ -2132,7 +281,7 @@ static void normalize16bitFloatSigned(float *fSampleData, uint32_t sampleLength) · 13 unmodified lines | ||
| 2132 | 281 | fSampleData[i] *= fGain; |
| 2133 | 282 | } |
| 2134 | 283 | |
| 2135 | −static void normalize64bitDoubleSigned(double *dSampleData, uint32_t sampleLength) | |
| 284 | +void normalize64BitFloatToSigned16Bit(double *dSampleData, uint32_t sampleLength) | |
| 2136 | 285 | { |
| 2137 | 286 | uint32_t i; |
| 2138 | 287 | |
| @@ -2151,98 +300,3 @@ static void normalize64bitDoubleSigned(double *dSampleData, uint32_t sampleLengt · 12 unmodified lines | ||
| 2151 | 300 | for (i = 0; i < sampleLength; i++) |
| 2152 | 301 | dSampleData[i] *= dGain; |
| 2153 | 302 | } |
| 2154 | − | |
| 2155 | −bool fileIsInstrument(char *fullPath) | |
| 2156 | −{ | |
| 2157 | − int32_t i, len; | |
| 2158 | − | |
| 2159 | − // this assumes that fullPath is not empty | |
| 2160 | − | |
| 2161 | − len = (int32_t)strlen(fullPath); | |
| 2162 | − | |
| 2163 | − // get filename from path | |
| 2164 | − i = len; | |
| 2165 | − while (i--) | |
| 2166 | − { | |
| 2167 | − if (fullPath[i] == DIR_DELIMITER) | |
| 2168 | − break; | |
| 2169 | − } | |
| 2170 | − | |
| 2171 | − char *filename = fullPath; | |
| 2172 | − if (i > 0) | |
| 2173 | − filename += i + 1; | |
| 2174 | − // -------------------------- | |
| 2175 | − | |
| 2176 | − len = (int32_t)strlen(filename); | |
| 2177 | − if (len < 4) | |
| 2178 | − return true; // can't be an instrument | |
| 2179 | − | |
| 2180 | − if (!_strnicmp("xi.", filename, 3) || (len >= 4 && !_strnicmp("pat.", filename, 4))) | |
| 2181 | − return true; | |
| 2182 | − | |
| 2183 | − int32_t extOffset = getExtOffset(filename, len); | |
| 2184 | − if (extOffset != -1) | |
| 2185 | − { | |
| 2186 | − if ((extOffset <= len-4) && !_strnicmp(".pat", &filename[extOffset], 4)) return true; | |
| 2187 | − if ((extOffset <= len-3) && !_strnicmp(".xi", &filename[extOffset], 3)) return true; | |
| 2188 | − } | |
| 2189 | − | |
| 2190 | − return false; | |
| 2191 | −} | |
| 2192 | − | |
| 2193 | −bool fileIsSample(char *fullPath) | |
| 2194 | −{ | |
| 2195 | − int32_t i, len; | |
| 2196 | − | |
| 2197 | − // this assumes that fullPath is not empty | |
| 2198 | − | |
| 2199 | − len = (int32_t)strlen(fullPath); | |
| 2200 | − | |
| 2201 | − // get filename from path | |
| 2202 | − i = len; | |
| 2203 | − while (i--) | |
| 2204 | − { | |
| 2205 | − if (fullPath[i] == DIR_DELIMITER) | |
| 2206 | − break; | |
| 2207 | − } | |
| 2208 | − | |
| 2209 | − char *filename = fullPath; | |
| 2210 | − if (i > 0) | |
| 2211 | − filename += i + 1; | |
| 2212 | − // -------------------------- | |
| 2213 | − | |
| 2214 | − len = (int32_t)strlen(filename); | |
| 2215 | − if (len < 4) | |
| 2216 | − return true; // can't be a module | |
| 2217 | − | |
| 2218 | − if (!_strnicmp("xm.", filename, 3) || !_strnicmp("ft.", filename, 3) || | |
| 2219 | − !_strnicmp("mod.", filename, 4) || !_strnicmp("nst.", filename, 4) || | |
| 2220 | − !_strnicmp("s3m.", filename, 4) || !_strnicmp("stm.", filename, 4) || | |
| 2221 | − !_strnicmp("fst.", filename, 4) || !_strnicmp("it.", filename, 3)) | |
| 2222 | − { | |
| 2223 | − return false; // definitely a module | |
| 2224 | − } | |
| 2225 | − | |
| 2226 | − int32_t extOffset = getExtOffset(filename, len); | |
| 2227 | − if (extOffset != -1) | |
| 2228 | − { | |
| 2229 | − if (extOffset <= len-4) | |
| 2230 | − { | |
| 2231 | − filename = &filename[extOffset]; | |
| 2232 | − if (!_strnicmp(".mod", filename, 4) || !_strnicmp(".nst", filename, 4) || | |
| 2233 | − !_strnicmp(".s3m", filename, 4) || !_strnicmp(".stm", filename, 4) || | |
| 2234 | − !_strnicmp(".fst", filename, 4)) | |
| 2235 | − { | |
| 2236 | − return false; // definitely a module | |
| 2237 | − } | |
| 2238 | − } | |
| 2239 | − else if (extOffset <= len-3) | |
| 2240 | − { | |
| 2241 | − filename = &filename[extOffset]; | |
| 2242 | − if (!_strnicmp(".xm", filename, 3) || !_strnicmp(".ft", filename, 3) || !_strnicmp(".it", filename, 3)) | |
| 2243 | − return false; // definitely a module | |
| 2244 | − } | |
| 2245 | − } | |
| 2246 | − | |
| 2247 | − return true; // let's assume it's a sample | |
| 2248 | −} | |