/* Function: al_load_ogg_vorbis_audio_stream_f */ ALLEGRO_AUDIO_STREAM *al_load_ogg_vorbis_audio_stream_f(ALLEGRO_FILE* file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggVorbis_File* vf; vorbis_info* vi; int channels; long rate; long total_samples; long total_size; AL_OV_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; extra = _AL_MALLOC(sizeof(AL_OV_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OV_DATA struct.\n"); return NULL; } if (file == NULL) { ALLEGRO_WARN("File failed to open\n"); fprintf(stderr, "File failed to open\n"); return NULL; } extra->file = file; vf = _AL_MALLOC(sizeof(OggVorbis_File)); if (ov_open_callbacks(extra, vf, NULL, 0, callbacks) < 0) { ALLEGRO_WARN("ogg: Input does not appear to be an Ogg bitstream.\n"); al_fclose(file); return NULL; } extra->vf = vf; vi = ov_info(vf, -1); channels = vi->channels; rate = vi->rate; total_samples = ov_pcm_total(vf,-1); total_size = total_samples * channels * word_size; extra->vi = vi; extra->bitstream = -1; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { free(vf); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->feed_thread = al_create_thread(_al_kcm_feed_stream, stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; al_start_thread(stream->feed_thread); return stream; }
/* Function: al_load_ogg_vorbis_f */ ALLEGRO_SAMPLE *al_load_ogg_vorbis_f(ALLEGRO_FILE* file) { /* Note: decoding library returns floats. I always return 16-bit (most * commonly supported). */ #ifdef ALLEGRO_LITTLE_ENDIAN const int endian = 0; /* 0 for Little-Endian, 1 for Big-Endian */ #else const int endian = 1; /* 0 for Little-Endian, 1 for Big-Endian */ #endif int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ int signedness = 1; /* 0 for unsigned, 1 for signed */ const int packet_size = 4096; /* suggestion for size to read at a time */ OggVorbis_File vf; vorbis_info* vi; char *buffer; long pos; ALLEGRO_SAMPLE *sample; int channels; long rate; long total_samples; int bitstream; long total_size; AL_OV_DATA ov; if (file == NULL) { ALLEGRO_WARN("Audio file failed to open.\n"); return NULL; } ov.file = file; if (ov_open_callbacks(&ov, &vf, NULL, 0, callbacks) < 0) { ALLEGRO_WARN("Audio file does not appear to be an Ogg bitstream.\n"); al_fclose(file); return NULL; } vi = ov_info(&vf, -1); channels = vi->channels; rate = vi->rate; total_samples = ov_pcm_total(&vf, -1); bitstream = -1; total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); buffer = _AL_MALLOC_ATOMIC(total_size); if (!buffer) { al_fclose(file); return NULL; } pos = 0; while (pos < total_size) { /* XXX error handling */ #if !defined(ALLEGRO_GP2XWIZ) && !defined(ALLEGRO_IPHONE) long read = ov_read(&vf, buffer + pos, packet_size, endian, word_size, signedness, &bitstream); #else (void)endian; (void)signedness; long read = ov_read(&vf, buffer + pos, packet_size, &bitstream); #endif pos += read; if (read == 0) break; } ov_clear(&vf); sample = al_create_sample(buffer, total_samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); if (!sample) { _AL_FREE(buffer); } return sample; }
ALLEGRO_SAMPLE *_al_load_ogg_opus_f(ALLEGRO_FILE *file) { /* Note: decoding library can return 16-bit or floating-point output, * both using native endian ordering. (TODO: Implement float output, * individual links in the stream...) */ int word_size = 2; /* 2 = 16-bit. */ const int packet_size = 5760; /* suggestion for size to read at a time */ OggOpusFile *of; opus_int16 *buffer; ALLEGRO_SAMPLE *sample; int channels; long rate; ogg_int64_t total_samples; int bitstream; ogg_int64_t total_size; AL_OP_DATA op; ogg_int64_t pos; long read; if (!init_dynlib()) { return NULL; } op.file = file; of = lib.op_open_callbacks(&op, &callbacks, NULL, 0, NULL); if (!of) { ALLEGRO_WARN("Audio file does not appear to be an Ogg bitstream.\n"); return NULL; } bitstream = -1; channels = lib.op_channel_count(of, bitstream); rate = 48000; total_samples = lib.op_pcm_total(of, bitstream); total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", (long)total_samples); ALLEGRO_DEBUG("total_size %ld\n", (long)total_size); buffer = al_malloc(total_size); if (!buffer) { return NULL; } pos = 0; while (pos < total_samples) { const int read_size = _ALLEGRO_MIN(packet_size, total_samples - pos); ASSERT(pos + read_size <= total_samples); /* XXX error handling */ read = lib.op_read(of, buffer + pos * channels, read_size, NULL); pos += read; if (read == 0) break; } lib.op_free(of); sample = al_create_sample(buffer, total_samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels), true); if (!sample) { al_free(buffer); } return sample; }
ALLEGRO_AUDIO_STREAM *_al_load_ogg_opus_audio_stream_f(ALLEGRO_FILE *file, size_t buffer_count, unsigned int samples) { const int word_size = 2; /* 1 = 8bit, 2 = 16-bit. nothing else */ OggOpusFile* of; int channels; long rate; long total_samples; long total_size; int bitstream; AL_OP_DATA* extra; ALLEGRO_AUDIO_STREAM* stream; if (!init_dynlib()) { return NULL; } extra = al_malloc(sizeof(AL_OP_DATA)); if (extra == NULL) { ALLEGRO_ERROR("Failed to allocate AL_OP_DATA struct.\n"); return NULL; } extra->file = file; of = lib.op_open_callbacks(extra, &callbacks, NULL, 0, NULL); if (!of) { ALLEGRO_WARN("ogg: Input does not appear to be an Ogg bitstream.\n"); return NULL; } extra->of = of; extra->bitstream = -1; bitstream = extra->bitstream; extra->channels = lib.op_channel_count(of, bitstream); channels = extra->channels; rate = 48000; total_samples = lib.op_pcm_total(of, bitstream); total_size = total_samples * channels * word_size; ALLEGRO_DEBUG("channels %d\n", channels); ALLEGRO_DEBUG("word_size %d\n", word_size); ALLEGRO_DEBUG("rate %ld\n", rate); ALLEGRO_DEBUG("total_samples %ld\n", total_samples); ALLEGRO_DEBUG("total_size %ld\n", total_size); stream = al_create_audio_stream(buffer_count, samples, rate, _al_word_size_to_depth_conf(word_size), _al_count_to_channel_conf(channels)); if (!stream) { lib.op_free(of); return NULL; } stream->extra = extra; extra->loop_start = 0.0; extra->loop_end = ogg_stream_get_length(stream); stream->quit_feed_thread = false; stream->feeder = ogg_stream_update; stream->rewind_feeder = ogg_stream_rewind; stream->seek_feeder = ogg_stream_seek; stream->get_feeder_position = ogg_stream_get_position; stream->get_feeder_length = ogg_stream_get_length; stream->set_feeder_loop = ogg_stream_set_loop; stream->unload_feeder = ogg_stream_close; _al_acodec_start_feed_thread(stream); return stream; }
ALLEGRO_SAMPLE *_al_load_voc_f(ALLEGRO_FILE *file) { AL_VOC_DATA *vocdata; ALLEGRO_SAMPLE *sample = NULL; size_t pos = 0; /* where to write in the buffer */ size_t read = 0; /*bytes read during last operation */ char* buffer; size_t bytestoread = 0; bool endofvoc = false; vocdata = al_malloc(sizeof(AL_VOC_DATA)); memset(vocdata, 0, sizeof(*vocdata)); /* * Open file and populate VOC DATA, then create a buffer for the number of * samples of the frst block. * Iterate on the following blocks till EOF or terminator block */ vocdata = voc_open(file); if (!vocdata) return NULL; ALLEGRO_DEBUG("channels %d\n", vocdata->channels); ALLEGRO_DEBUG("word_size %d\n", vocdata->sample_size); ALLEGRO_DEBUG("rate %d\n", vocdata->samplerate); ALLEGRO_DEBUG("first_block_samples %d\n", vocdata->samples); ALLEGRO_DEBUG("first_block_size %d\n", vocdata->samples * vocdata->sample_size); /* * Let's allocate at least the first block's bytes; */ buffer = al_malloc(vocdata->samples * vocdata->sample_size); if (!buffer) { return NULL; } /* * We now need to iterate over data blocks till either we hit end of file * or we find a terminator block. */ bytestoread = vocdata->samples * vocdata->sample_size; while(!endofvoc && !al_feof(vocdata->file)) { uint32_t blocktype = 0; uint32_t x = 0, len = 0; read = al_fread(vocdata->file, buffer, bytestoread); pos += read; READNBYTES(vocdata->file, blocktype, 1, NULL); // read next block type if (al_feof(vocdata->file)) break; switch (blocktype) { case 0:{ /* we found a terminator block */ endofvoc = true; break; } case 2:{ /*we found a continuation block: unlikely but handled */ x = 0; bytestoread = 0; READNBYTES(vocdata->file, bytestoread, 2, NULL); READNBYTES(vocdata->file, x, 1, NULL); bytestoread += x<<16; /* increase subsequently storage */ buffer = al_realloc(buffer, sizeof(buffer) + bytestoread); break; } case 1: // we found a NEW data block starter, I assume this is wrong case 8: // and let the so far read sample data correctly in the case 9:{ // already allocated buffer. endofvoc = true; break; } case 3: /* we found a pause block */ case 4: /* we found a marker block */ case 5: /* we found an ASCII c-string block */ case 6: /* we found a repeat block */ case 7:{ /* we found an end repeat block */ /* all these blocks will be skipped */ unsigned int ii; len = 0; x = 0; READNBYTES(vocdata->file, len, 2, NULL); READNBYTES(vocdata->file, x, 1, NULL); len += x<<16; // this is the length what's left to skip */ for (ii = 0; ii < len ; ++ii) { al_fgetc(vocdata->file); } bytestoread = 0; //should let safely check for the next block */ break; } default: break; } } sample = al_create_sample(buffer, pos, vocdata->samplerate, _al_word_size_to_depth_conf(vocdata->sample_size), _al_count_to_channel_conf(vocdata->channels), true); if (!sample) al_free(buffer); voc_close(vocdata); return sample; }