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; }
static UINT mp3_dec(GETSND snd, short *dst) { UINT8 *src; MPEGL3 *mp3; int r; src = snd->datptr; mp3 = (MPEGL3 *)snd->snd; if (snd->datsize < 4) { goto mp3dec_err; } r = mp3_predecode(mp3, src); if (r) { if ((r != MPEGHEAD_RENEWAL) || (snd->samplingrate != mp3->c.samplingrate) || (snd->channels != mp3->c.channels)) { TRACEOUT(("mp3 decord err")); goto mp3dec_err; } } if (snd->datsize < mp3->c.insize) { goto mp3dec_err; } snd->datptr += mp3->c.insize; snd->datsize -= mp3->c.insize; mp3_decode(mp3, dst, src, mp3->c.insize); return(mp3->c.outsamples); mp3dec_err: return(0); }
/* Read some data from the mp3 file stream */ static adv_error mp3_read_stream(unsigned channel) { if (mixer_map[channel].pos == mixer_map[channel].start) { return mp3_first_read_stream(channel); } else { unsigned char data[MIXER_PAGE_SIZE]; unsigned run = mp3_read_data(channel, data, MIXER_PAGE_SIZE); if (!run) { return -1; } mp3_decode(&mixer_map[channel].mp3, data, run, 0, 0, 0); return 0; } }
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; }
static adv_error mixer_mp3_pump(unsigned channel) { unsigned char buffer[2304*4]; /* 2304 samples for MP3 frame */ unsigned nmin; unsigned nmax; int bytes_done; int err; if (mixer_channel_input_is_empty(channel)) return -1; if (mixer_map[channel].rate) { /* check for avaiable space */ mixer_channel_need(channel, &nmin, &nmax); /* no space */ if (nmax < 2304) return -1; /* no need */ if (nmin == 0) return -1; } bytes_done = 0; err = mp3_decode(&mixer_map[channel].mp3, 0, 0, buffer, sizeof(buffer)/2, &bytes_done); /* insert data until it's required */ while (err == MP3_NEED_MORE && mp3_read_stream(channel)==0) { err = mp3_decode(&mixer_map[channel].mp3, 0, 0, buffer, sizeof(buffer)/2, &bytes_done); } if (err == MP3_NEED_MORE) { /* end of the stream */ mixer_map[channel].empty = 1; return -1; } if (err != MP3_OK) { /* generic error */ mixer_channel_abort(channel); return -1; } if (!bytes_done) /* no data ? exit */ return 0; /* delayed set of the channel */ if (!mixer_map[channel].rate) { unsigned rate; unsigned nchannel; unsigned bit; rate = mp3_freqs[mixer_map[channel].mp3.fr.sampling_frequency]; nchannel = mixer_map[channel].mp3.fr.stereo; /* this is correct, stereo is the number of channel */ bit = 16; mixer_channel_set(channel, rate, nchannel, bit); } /* override the nchannel value */ if (mixer_map[channel].mp3.fr.stereo == 1) { mixer_channel_mix_mono16(channel, buffer, bytes_done / 2); } else { mixer_channel_mix_stereo16(channel, buffer, bytes_done / 4); } return 0; }
static adv_error mp3_first_read_stream(unsigned channel) { unsigned char data[MIXER_PAGE_SIZE]; unsigned pos = 0; unsigned run = mp3_read_data(channel, data, MIXER_PAGE_SIZE); if (!run) { return -1; } if (run>=12 && data[0]=='R' && data[1]=='I' && data[2]=='F' && data[3]=='F' && data[8]=='W' && data[9]=='A' && data[10]=='V' && data[11]=='E') { /* RIFF header */ unsigned char id[4]; log_std(("mixer: skip RIFF header\n")); if (mp3_skip(channel, 12, data, &pos, &run) != 0) return -1; if (mp3_read_id(id, channel, data, &pos, &run) != 0) return -1; while (memcmp(id, "data", 4)!=0) { unsigned size; if (mp3_read_le32(&size, channel, data, &pos, &run) != 0) return -1; if (size % 2) size += 1; if (mp3_skip(channel, size, data, &pos, &run) != 0) return -1; if (mp3_read_id(id, channel, data, &pos, &run) != 0) return -1; } if (mp3_skip(channel, 4, data, &pos, &run) != 0) return -1; } else if (run>=10 && data[0]=='I' && data[1]=='D' && data[2]=='3' && data[3]!=0xFF && data[4]!=0xFF && (data[6] & 0x80) == 0 && (data[7] & 0x80) == 0 && (data[8] & 0x80) == 0 && (data[9] & 0x80) == 0) { /* ID3 tag header */ unsigned size = (unsigned)data[9] | (((unsigned)data[8]) << 7) | (((unsigned)data[7]) << 14) | (((unsigned)data[6]) << 21); size += 10; log_std(("mixer: skip ID3 header %d\n", size)); if (mp3_skip(channel, size, data, &pos, &run) != 0) return -1; } if (run>=4 && !mp3_is_valid(data + pos)) return -1; /* insert the data */ if (run) mp3_decode(&mixer_map[channel].mp3, data + pos, run, 0, 0, 0); return 0; }