kwlError kwlEventInstance_createFreeformEventFromFile(kwlEventInstance** event, const char* const audioFilePath, kwlEventType type, int streamFromDisk) { KWL_ASSERT(streamFromDisk == 0 && "stream flag not supported yet"); /*try to load the audio file data*/ kwlAudioData* audioData = (kwlAudioData*)KWL_MALLOC(sizeof(kwlAudioData), "freeform event audio data struct"); kwlMemset(audioData, 0, sizeof(kwlAudioData)); kwlError error = kwlLoadAudioFile(audioFilePath, audioData, KWL_CONVERT_TO_INT16_OR_FAIL); if (error != KWL_NO_ERROR) { KWL_FREE(audioData); return error; } if (type == KWL_POSITIONAL && audioData->numChannels != 1) { kwlAudioData_free(audioData); KWL_FREE(audioData); return KWL_POSITIONAL_EVENT_MUST_BE_MONO; } return kwlEventInstance_createFreeformEventFromAudioData(event, audioData, type, "freeform event"); }
void kwlMixBus_dealloc(kwlMixBus* mixBus) { if (mixBus->id != NULL) { KWL_FREE(mixBus->id); } KWL_FREE(mixBus); }
void kwlEventInstance_releaseFreeformEvent(kwlEventInstance* event) { /*Free all data associated with the freeform event.*/ kwlEventDefinition* eventDefinition = event->definition_engine; if (eventDefinition->streamAudioData != NULL) { KWL_ASSERT(0); /* double check this*/ kwlAudioData_free(eventDefinition->streamAudioData); KWL_FREE(eventDefinition->streamAudioData); } else if (eventDefinition->sound != NULL) { /*TODO: this check could be more robust. it will cause a memory leak for freeform events created from files with the name "freeform buffer event"*/ if (strcmp(eventDefinition->id, "freeform buffer event") == 0) { /*don't release audio data buffer for freeform buffer events.*/ eventDefinition->sound->audioDataEntries[0]->bytes = NULL; } /* Free loaded audio data */ kwlAudioData_free(eventDefinition->sound->audioDataEntries[0]); /* Free allocated audio data and sound structs */ KWL_FREE(eventDefinition->sound->audioDataEntries[0]); KWL_FREE(eventDefinition->sound->audioDataEntries); KWL_FREE(eventDefinition->sound); } /* Finally, free the event instance and the event definition. */ KWL_FREE(eventDefinition); KWL_FREE(event); }
void kwlDecoder_deinit(kwlDecoder* decoder) { /*Shut down the decoder.*/ decoder->threadJoinRequested = 1; kwlSemaphorePost(decoder->semaphore); kwlThreadJoin(&decoder->decodingThread); /*Dispose of the semaphore.*/ kwlSemaphoreDestroy(decoder->semaphore, decoder->semaphoreName); /*Free back and front buffers.*/ KWL_FREE(decoder->currentDecodedBuffer); KWL_FREE(decoder->currentDecodedBufferFront); /*Close input stream*/ kwlInputStream_close(&decoder->audioDataStream); /*Codec specific cleanup.*/ decoder->deinit(decoder); decoder->codecData = NULL; }
void kwlWaveBank_unload(kwlWaveBank* waveBank) { if (waveBank->isLoaded == 0) { return; } /* Free all allocated audio data in the wave bank*/ const int numAudioDataEntriesInBank = waveBank->numAudioDataEntries; int i; for (i = 0; i < numAudioDataEntriesInBank; i++) { kwlAudioData* wavei = &waveBank->audioDataItems[i]; kwlAudioData_free(wavei); } waveBank->isLoaded = 0; KWL_FREE(waveBank->waveBankFilePath); }
kwlError kwlWaveBank_verifyWaveBankBinary(kwlEngine* engine, const char* const waveBankPath, kwlWaveBank** waveBank) { /*Open the file...*/ kwlInputStream stream; kwlError result = kwlInputStream_initWithFile(&stream, waveBankPath); if (result != KWL_NO_ERROR) { kwlInputStream_close(&stream); return result; } /*... and check the wave bank file identifier.*/ int i; for (i = 0; i < KWL_WAVE_BANK_BINARY_FILE_IDENTIFIER_LENGTH; i++) { const char identifierChari = kwlInputStream_readChar(&stream); if (identifierChari != KWL_WAVE_BANK_BINARY_FILE_IDENTIFIER[i]) { /* Not the file identifier we expected. */ kwlInputStream_close(&stream); return KWL_UNKNOWN_FILE_FORMAT; } } /*Read the ID from the wave bank binary file and find a matching wave bank struct.*/ const char* waveBankToLoadId = kwlInputStream_readASCIIString(&stream); const int waveBankToLoadnumAudioDataEntries = kwlInputStream_readIntBE(&stream); const int numWaveBanks = engine->engineData.numWaveBanks; kwlWaveBank* matchingWaveBank = NULL; for (i = 0; i < numWaveBanks; i++) { if (strcmp(waveBankToLoadId, engine->engineData.waveBanks[i].id) == 0) { matchingWaveBank = &engine->engineData.waveBanks[i]; } } KWL_FREE((void*)waveBankToLoadId); if (matchingWaveBank == NULL) { /*No matching bank was found. Close the file stream and return an error.*/ kwlInputStream_close(&stream); return KWL_NO_MATCHING_WAVE_BANK; } else if (waveBankToLoadnumAudioDataEntries != matchingWaveBank->numAudioDataEntries) { /*A matching wave bank was found but the number of audio data entries does not match the binary wave bank data.*/ kwlInputStream_close(&stream); return KWL_WAVE_BANK_ENTRY_MISMATCH; } else if (matchingWaveBank->isLoaded != 0) { /*The wave bank is already loaded, just set the handle and do nothing.*/ *waveBank = matchingWaveBank; kwlInputStream_close(&stream); return KWL_NO_ERROR; } /*Store the path the wave bank was loaded from (used when streaming from disk).*/ const int pathLen = strlen(waveBankPath); matchingWaveBank->waveBankFilePath = (char*)KWL_MALLOC((pathLen + 1) * sizeof(char), "wave bank path string"); strcpy(matchingWaveBank->waveBankFilePath, waveBankPath); /*Make sure that the entries of the wave bank to load and the wave bank struct line up.*/ for (i = 0; i < waveBankToLoadnumAudioDataEntries; i++) { const char* filePathi = kwlInputStream_readASCIIString(&stream); int matchingEntryIndex = -1; int j = 0; for (j = 0; j < waveBankToLoadnumAudioDataEntries; j++) { if (strcmp(matchingWaveBank->audioDataItems[j].filePath, filePathi) == 0) { matchingEntryIndex = j; break; } } KWL_FREE((void*)filePathi); if (matchingEntryIndex < 0) { /* This wave bank entry has no corresponding waveform slot. Abort loading.*/ kwlInputStream_close(&stream); return KWL_WAVE_BANK_ENTRY_MISMATCH; } /*skip to the next wave data entry*/ /*const int encoding = */kwlInputStream_readIntBE(&stream); /*const int streamFromDisk = */kwlInputStream_readIntBE(&stream); const int numChannels = kwlInputStream_readIntBE(&stream); KWL_ASSERT((numChannels == 0 || numChannels == 1 || numChannels == 2) && "invalid num channels"); const int numBytes = kwlInputStream_readIntBE(&stream); KWL_ASSERT(numBytes > 0); kwlInputStream_skip(&stream, numBytes); } /* Reading went well. */ kwlInputStream_close(&stream); *waveBank = matchingWaveBank; return KWL_NO_ERROR; }
kwlError kwlWaveBank_loadAudioDataItems(kwlWaveBank* waveBank, kwlInputStream* stream) { /*The input stream is assumed to be valid, so move the read position to the first audio data entry.*/ kwlInputStream_reset(stream); kwlInputStream_skip(stream, KWL_WAVE_BANK_BINARY_FILE_IDENTIFIER_LENGTH); const int strLen = kwlInputStream_readIntBE(stream); kwlInputStream_skip(stream, strLen); /*int numEntries = */kwlInputStream_readIntBE(stream); const int waveBankToLoadnumAudioDataEntries = waveBank->numAudioDataEntries; for (int i = 0; i < waveBankToLoadnumAudioDataEntries; i++) { char* const waveEntryIdi = kwlInputStream_readASCIIString(stream); kwlAudioData* matchingAudioData = NULL; int j; for (int j = 0; j < waveBankToLoadnumAudioDataEntries; j++) { kwlAudioData* entryj = &waveBank->audioDataItems[j]; if (strcmp(entryj->filePath, waveEntryIdi) == 0) { matchingAudioData = entryj; break; } } //printf(" loading %s\n", waveEntryIdi); KWL_FREE(waveEntryIdi); const kwlAudioEncoding encoding = (kwlAudioEncoding)kwlInputStream_readIntBE(stream); const int streamFromDisk = kwlInputStream_readIntBE(stream); const int numChannels = kwlInputStream_readIntBE(stream); const int numBytes = kwlInputStream_readIntBE(stream); const int numFrames = numBytes / 2 * numChannels; /* Check that the audio meta data makes sense */ if (numBytes <= 0) { KWL_ASSERT(0 && "the number of audio data bytes must be positive"); return KWL_CORRUPT_BINARY_DATA; } if (matchingAudioData == NULL) { KWL_ASSERT(0 && "no matching wave bank entry"); return KWL_CORRUPT_BINARY_DATA; } if (numChannels != 0 && numChannels != 1 && numChannels != 2) { KWL_ASSERT(0 && "invalid number of channels"); return KWL_CORRUPT_BINARY_DATA; } /*free any old data*/ kwlAudioData_free(matchingAudioData); /*Store audio meta data.*/ matchingAudioData->numFrames = numFrames; matchingAudioData->numChannels = numChannels; matchingAudioData->numBytes = numBytes; matchingAudioData->encoding = (kwlAudioEncoding)encoding; matchingAudioData->streamFromDisk = streamFromDisk; matchingAudioData->isLoaded = 1; matchingAudioData->bytes = NULL; if (streamFromDisk == 0) { /*This entry should not be streamed, so allocate audio data up front.*/ matchingAudioData->bytes = KWL_MALLOC(numBytes, "kwlEngine_loadWaveBank"); int bytesRead = kwlInputStream_read(stream, (signed char*)matchingAudioData->bytes, numBytes); if (bytesRead != numBytes) { KWL_ASSERT(0 && "error reading wave bank audio data bytes"); return KWL_CORRUPT_BINARY_DATA; } } else { /*Store the offset into the wave bank binary files for streaming entries.*/ matchingAudioData->fileOffset = kwlInputStream_tell(stream); kwlInputStream_skip(stream, numBytes); } } waveBank->isLoaded = 1; return KWL_NO_ERROR; }