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");
}
Beispiel #2
0
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);
}
Beispiel #4
0
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;
}