snd_sequence_struct *snd_decode_mp3(uint8 *buffer,int32 bytes){ mp3_decoder_t mp3; mp3_info_t info; memset(&info,0,sizeof(mp3_info_t)); unsigned char *stream_pos; int bytes_left; int bytes_read; int sample_buffer_allocated_bytes=2000000; int16* sample_buffer=(int16*)malloc(2000000); int16* sample_buffer_offset; bytes_left=bytes; stream_pos=(unsigned char*)buffer; mp3 = mp3_create(); int bytes_out=0; int firstTry=1; sample_buffer_offset=sample_buffer; mp3getmore: bytes_read = mp3_decode((void**)mp3, stream_pos, bytes_left, sample_buffer_offset, &info); if (firstTry==1 && info.audio_bytes<=0){ free(sample_buffer); return NULL; } firstTry=0; bytes_left-=bytes_read; stream_pos+=bytes_read; sample_buffer_offset=(int16*)(((uint8*)sample_buffer_offset)+info.audio_bytes); bytes_out+=info.audio_bytes; if (bytes_out+1000000>sample_buffer_allocated_bytes){ sample_buffer_allocated_bytes+=1000000; sample_buffer=(int16*)realloc(sample_buffer,sample_buffer_allocated_bytes); sample_buffer_offset=(int16*)(((uint8*)sample_buffer)+bytes_out); } if (bytes_left>0 && bytes_read!=0) goto mp3getmore; //attach bufout to new sequence static int32 seq_handle; seq_handle=list_add(snd_sequences); static snd_sequence_struct *seq; seq=(snd_sequence_struct*)list_get(snd_sequences,seq_handle); memset(seq,0,sizeof(snd_sequence_struct)); seq->references=1; seq->data=(uint8*)sample_buffer; seq->data_size=bytes_out; seq->channels=info.channels; seq->endian=0;//native seq->is_unsigned=0; seq->sample_rate=info.sample_rate; seq->bits_per_sample=16; return seq; }
BRESULT __mp3_open(GETSND snd, UINT8 *ptr, UINT size) { MPEGL3 *mp3; if (size < 4) { goto mp3opn_err; } mp3 = mp3_create(ptr); if (mp3 == NULL) { goto mp3opn_err; } snd->datptr = ptr; snd->datsize = size; snd->snd = mp3; snd->dec = (GSDEC)mp3_dec; snd->decend = mp3_decend; snd->samplingrate = mp3->c.samplingrate; snd->channels = mp3->c.channels; snd->blocksize = 1728; snd->blocksamples = mp3->c.outsamples; snd->bit = 16; TRACEOUT(("mp3: %dHz %dkbps", mp3->c.samplingrate, mp3->c.kbitrate)); return(SUCCESS); mp3opn_err: return(FAILURE); }
void *loom_asset_soundDeserializer( void *buffer, size_t bufferLen, LoomAssetCleanupCallback *dtor ) { loom_asset_sound_t *sound = (loom_asset_sound_t*)lmAlloc(gAssetAllocator, sizeof(loom_asset_sound_t)); memset(sound, 0, sizeof(loom_asset_sound_t)); unsigned char *charBuff = (unsigned char *)buffer; // Look for magic header in buffer. if(charBuff[0] == 0x4f && charBuff[1] == 0x67 && charBuff[2] == 0x67 && charBuff[3] == 0x53) { // It's an Ogg, assume vorbis and throw it to stb_vorbis. int channels = 0; short *outputBuffer = NULL; int sampleCount = stb_vorbis_decode_memory(charBuff, (int)bufferLen, &channels, &outputBuffer); if(sampleCount < 0) { lmLogError(gSoundAssetGroup, "Failed to decode Ogg Vorbis"); loom_asset_soundDtor(&sound); return NULL; } sound->channels = channels; sound->bytesPerSample = 2; sound->sampleCount = sampleCount; sound->bufferSize = sampleCount * channels * 2; sound->sampleRate = 44100; // TODO: This should be variable // We can skip this if we get clever about allocations in stbv. sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize); memcpy(sound->buffer, outputBuffer, sound->bufferSize); free(outputBuffer); } else if((charBuff[0] == 0x49 // ID3 && charBuff[1] == 0x44 && charBuff[2] == 0x33) || (charBuff[0] == 0xff // Missing ID3 Tag && charBuff[1] == 0xfb)) { // It's an MP3, y'all! short *outBuffer = (short*)lmAlloc(gAssetAllocator, MP3_MAX_SAMPLES_PER_FRAME * 2); mp3_info_t mp3Info; // Decode once to get total size. size_t totalBytes = 0; size_t bytesRead = 0, bytesLeft = bufferLen; mp3_decoder_t decmp3 = mp3_create(); for(;;) { int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, (int)bytesLeft, outBuffer, &mp3Info); bytesRead += bytesDecoded; bytesLeft -= bytesDecoded; totalBytes += mp3Info.audio_bytes; if(bytesDecoded > 0) continue; // Clean up. mp3_done(decmp3); break; } // Great, set up the sound asset. // TODO: Warn about non 44.1khz mp3s. sound->channels = mp3Info.channels; sound->bytesPerSample = 2; sound->sampleCount = (int)totalBytes / sound->bytesPerSample; sound->bufferSize = sound->channels * sound->bytesPerSample * sound->sampleCount; sound->sampleRate = 44100; // TODO: This should be variable sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize); // Decode again to get real samples. decmp3 = mp3_create(); bytesRead = 0; bytesLeft = bufferLen; int curBufferOffset = 0; for(;;) { int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, (int)bytesLeft, outBuffer, &mp3Info); bytesRead += bytesDecoded; bytesLeft -= bytesDecoded; memcpy(((unsigned char*)sound->buffer) + curBufferOffset, outBuffer, mp3Info.audio_bytes); curBufferOffset += mp3Info.audio_bytes; if(bytesDecoded > 0) continue; // Clean up. mp3_done(decmp3); break; } // Awesome, all set! lmFree(gAssetAllocator, outBuffer); } else if(charBuff[0] == 0x52 // 'RIFF' && charBuff[1] == 0x49 && charBuff[2] == 0x46 && charBuff[3] == 0x46) { // We've got a wav file wav_info wav; bool wavLoadSuccess = load_wav(charBuff, bufferLen, NULL, &wav); if (!wavLoadSuccess) { lmLogError(gSoundAssetGroup, "Failed to load wav format info"); loom_asset_soundDtor(sound); return 0; } sound->channels = wav.numChannels; sound->bytesPerSample = wav.sampleSize / 8; // wav sample size is in bits if (sound->bytesPerSample != 1 && sound->bytesPerSample != 2) { lmLogError(gSoundAssetGroup, "Unsupported wav format. Currently only 8-bit or 16-bit PCM are supported"); loom_asset_soundDtor(sound); return 0; } sound->bufferSize = wav.sampleDataSize; sound->sampleCount = sound->bufferSize / sound->bytesPerSample; sound->sampleRate = wav.samplesPerSecond; sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize); bool dataCopySuccess = load_wav(charBuff, bufferLen, (uint8_t*)sound->buffer, NULL); if (!dataCopySuccess) { lmLogError(gSoundAssetGroup, "Failed to copy wav data"); loom_asset_soundDtor(sound); return 0; } } else { lmLogError(gSoundAssetGroup, "Failed to identify sound buffer by magic number!"); loom_asset_soundDtor(sound); return 0; } *dtor = loom_asset_soundDtor; if(!sound->buffer) { lmLogError(gSoundAssetGroup, "Sound load failed due to this cryptic reason: %s", "(unknown)"); lmFree(gAssetAllocator, sound); return 0; } lmLogDebug(gSoundAssetGroup, "Sound allocation: %d bytes", sound->bufferSize); return sound; }
void *loom_asset_soundDeserializer( void *buffer, size_t bufferLen, LoomAssetCleanupCallback *dtor ) { loom_asset_sound_t *sound = (loom_asset_sound_t*)lmAlloc(gAssetAllocator, sizeof(loom_asset_sound_t)); unsigned char *charBuff = (unsigned char *)buffer; // Look for magic header in buffer. if(charBuff[0] == 0x4f && charBuff[1] == 0x67 && charBuff[2] == 0x67 && charBuff[3] == 0x53) { // It's an Ogg, assume vorbis and throw it to stb_vorbis. int channels = 0; short *outputBuffer = NULL; int sampleCount = stb_vorbis_decode_memory(charBuff, bufferLen, &channels, &outputBuffer); if(sampleCount < 0) { lmLogError(gSoundAssetGroup, "Failed to decode Ogg Vorbis!"); return NULL; } sound->channels = channels; sound->bytesPerSample = 2; sound->sampleCount = sampleCount; sound->bufferSize = sampleCount * channels * 2; // We can skip this if we get clever about allocations in stbv. sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize); memcpy(sound->buffer, outputBuffer, sound->bufferSize); free(outputBuffer); } else if((charBuff[0] == 0x49 // ID3 && charBuff[1] == 0x44 && charBuff[2] == 0x33) || (charBuff[0] == 0xff // Missing ID3 Tag && charBuff[1] == 0xfb)) { // It's an MP3, y'all! short *outBuffer = (short*)lmAlloc(gAssetAllocator, MP3_MAX_SAMPLES_PER_FRAME * 2); mp3_info_t mp3Info; // Decode once to get total size. int totalBytes = 0; int bytesRead = 0, bytesLeft = bufferLen; mp3_decoder_t decmp3 = mp3_create(); for(;;) { int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, bytesLeft, outBuffer, &mp3Info); bytesRead += bytesDecoded; bytesLeft -= bytesDecoded; totalBytes += mp3Info.audio_bytes; if(bytesDecoded > 0) continue; // Clean up. mp3_done(decmp3); break; } // Great, set up the sound asset. // TODO: Warn about non 44.1khz mp3s. sound->channels = mp3Info.channels; sound->bytesPerSample = 2; sound->sampleCount = totalBytes / sound->bytesPerSample; sound->bufferSize = sound->channels * sound->bytesPerSample * sound->sampleCount; sound->buffer = lmAlloc(gAssetAllocator, sound->bufferSize); // Decode again to get real samples. decmp3 = mp3_create(); bytesRead = 0; bytesLeft = bufferLen; int curBufferOffset = 0; for(;;) { int bytesDecoded = mp3_decode(decmp3, charBuff + bytesRead, bytesLeft, outBuffer, &mp3Info); bytesRead += bytesDecoded; bytesLeft -= bytesDecoded; memcpy(((unsigned char*)sound->buffer) + curBufferOffset, outBuffer, mp3Info.audio_bytes); curBufferOffset += mp3Info.audio_bytes; if(bytesDecoded > 0) continue; // Clean up. mp3_done(decmp3); break; } // Awesome, all set! lmFree(gAssetAllocator, outBuffer); } else { lmLogError(gSoundAssetGroup, "Failed to identify sound buffer by magic number!"); return 0; } *dtor = loom_asset_soundDtor; if(!sound->buffer) { lmLogError(gSoundAssetGroup, "Sound load failed due to this cryptic reason: %s", "(unknown)"); lmFree(gAssetAllocator, sound); return 0; } lmLogError(gSoundAssetGroup, "Allocated %d bytes for a sound!", sound->bufferSize); return sound; }