void test_push_mode_forever(FILE *g, char *filename) { int p,q, len, error, used; uint8 *data = stb_file(filename, &len); stb_vorbis *v; if (!data) stb_fatal("Couldn't open {%s}", filename); p = 0; q = 1; retry: v = stb_vorbis_open_pushdata(data, q, &used, &error, NULL); if (v == NULL) { if (error == VORBIS_need_more_data) { q += 1; goto retry; } printf("Error %d\n", error); exit(1); } p += used; show_info(v); for(;;) { int k=0; int n; float *left, *right; float **outputs; int num_c; q = 32; retry3: if (q > len-p) q = len-p; used = stb_vorbis_decode_frame_pushdata(v, data+p, q, &num_c, &outputs, &n); if (used == 0) { if (p+q == len) { // seek randomly when at end... this makes sense when listening to it, but dumb when writing to file p = stb_rand(); if (p < 0) p = -p; p %= (len - 8000); stb_vorbis_flush_pushdata(v); q = 128; goto retry3; } if (q < 128) q = 128; q *= 2; goto retry3; } p += used; if (n == 0) continue; left = outputs[0]; right = num_c > 1 ? outputs[1] : outputs[0]; write_floats(g, n, left, right); } stb_vorbis_close(v); }
// in push mode, you can load your data any way you want, then // feed it a little bit at a time. this is the preferred way to // handle reading from a packed file or some custom stream format; // instead of putting callbacks inside stb_vorbis, you just keep // a little buffer (it needs to be big enough for one packet of // audio, except at the beginning where you need to buffer up the // entire header). // // for this test, I just load all the data and just lie to stb_vorbis // and claim I only have a little of it void test_decode_frame_pushdata(FILE *g, char *filename) { int p,q, len, error, used; stb_vorbis *v; uint8 *data = stb_file(filename, &len); if (!data) stb_fatal("Couldn't open {%s}", filename); p = 0; q = 1; retry: v = stb_vorbis_open_pushdata(data, q, &used, &error, NULL); if (v == NULL) { if (error == VORBIS_need_more_data) { q += 1; goto retry; } fprintf(stderr, "Error %d\n", error); exit(1); } p += used; show_info(v); for(;;) { int k=0; int n; float *left, *right; uint32 next_t=0; float **outputs; int num_c; q = 32; retry3: if (q > len-p) q = len-p; used = stb_vorbis_decode_frame_pushdata(v, data+p, q, &num_c, &outputs, &n); if (used == 0) { if (p+q == len) break; // no more data, stop if (q < 128) q = 128; q *= 2; goto retry3; } p += used; if (n == 0) continue; // seek/error recovery left = outputs[0]; right = num_c > 1 ? outputs[1] : outputs[0]; write_floats(g, n, left, right); } stb_vorbis_close(v); }
S32 PCMAudioManager::playStreamingSound(const char *assetName, S16 loops, F32 leftVol, F32 rightVol, F32 rate) { if (leftVol < 0) { leftVol = 0; } else if (leftVol > 1) { leftVol = 1; } if (rightVol < 0) { rightVol = 0; } else if (rightVol > 1) { rightVol = 1; } S32 streamId = -1; //char buf[50]; //sprintf(buf, "Playing sound %i", soundId); //logmsg(buf); // create a stream BOOL32 success = FALSE; for (S32 i = 0; i < streamCount; i++) { PCMStream *stream = &pcmStreams[i]; if (!stream->isPlaying && !stream->audioHandle) { //sprintf(buf, "Using Stream %i", i); //logmsg(buf); // use this stream; stream->isStreaming = TRUE; stream->pcmSound = NULL; stream->loopsRemaining = loops; stream->bufferPosition = 0; stream->overallPosition = 0; streamId = ++lastStreamId; stream->streamId = streamId; stream->volumeLeft = leftVol; stream->volumeRight = rightVol; stream->assetName = strDuplicate(assetName); stream->channels = 0; stream->playbackRate = rate; stream->filePosition = 0; stream->assetLength = _platform_get_asset_length(assetName); if (stream->assetLength > 0) { // get vorbis handle and read info // fill both audio buffers if (!stream->audioBuf) { stream->audioBuf = new S16*[PCM_AUDIO_STREAM_BUFFERS]; for (S32 j = 0; j < PCM_AUDIO_STREAM_BUFFERS; j++) { stream->audioBuf[j] = new S16[PCM_AUDIO_STREAM_BUFFER_SIZE]; } } unsigned char buf[CHUNKED_READ_BUFFER_SIZE]; BOOL32 eof = FALSE; S32 bytesRead = _platform_read_asset_chunk(assetName, 0, buf, CHUNKED_READ_BUFFER_SIZE, &eof); S32 bytesConsumed; S32 error; // start vorbis pushdata stb_vorbis *vorb = stb_vorbis_open_pushdata(buf, bytesRead, &bytesConsumed, &error, NULL); stb_vorbis_info info = stb_vorbis_get_info(vorb); stream->channels = info.channels; stream->sampleRate = info.sample_rate; stream->maxFrameSize = info.max_frame_size; stream->length = 0; // unknown until we hit eof stream->tempLength = 0; stream->filePosition = bytesConsumed; stream->audioHandle = vorb; stream->resampleActiveRate = stream->sampleRate * stream->playbackRate; stream->resampleInt = stream->resampleActiveRate / PCM_AUDIO_PLAYBACK_RATE; stream->resampleFrac = stream->resampleActiveRate % PCM_AUDIO_PLAYBACK_RATE; stream->resampleFracAccumulated = 0; for (S32 j = 0; j < PCM_AUDIO_STREAM_BUFFERS; j++) { fillStreamingBuffer(stream, j); } stream->activeAudioBuf = 0; // set isPlaying to true last stream->isPlaying = TRUE; } success = TRUE; break; } } if (!success) { logmsg("No streams left to play on"); } return streamId; }