int __declspec(dllexport) DLL_FillBuffer(long vgm, char* szBuffer, int iSize) { VGMSTREAM* song = (VGMSTREAM*)vgm; render_vgmstream((sample*)szBuffer,iSize/(2*song->channels),(VGMSTREAM*)vgm); return iSize; }
int64_t Seek(void* context, int64_t time) { if (!context) return 0; VGMContext* ctx = (VGMContext*)context; int16_t* buffer = new int16_t[576*ctx->stream->channels]; if (!buffer) return 0; long samples_to_do = (long)time * ctx->stream->sample_rate / 1000L; if (samples_to_do < ctx->stream->current_sample ) reset_vgmstream(ctx->stream); else samples_to_do -= ctx->stream->current_sample; while (samples_to_do > 0) { long l = samples_to_do>576?576:samples_to_do; render_vgmstream(buffer, l, ctx->stream); samples_to_do -= l; } delete[] buffer; return time; }
void render_vgmstream_scd_int(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { sample interleave_buf[INTERLEAVE_BUF_SIZE]; int32_t samples_done = 0; scd_int_codec_data *data = vgmstream->codec_data; while (samples_done < sample_count) { int32_t samples_to_do = INTERLEAVE_BUF_SIZE; int c; if (samples_to_do > sample_count - samples_done) samples_to_do = sample_count - samples_done; for (c=0; c < data->substream_count; c++) { int32_t i; render_vgmstream(interleave_buf, samples_to_do, data->substreams[c]); for (i=0; i < samples_to_do; i++) { buffer[(samples_done+i)*data->substream_count + c] = interleave_buf[i]; } } samples_done += samples_to_do; } }
/* Decodes samples for segmented streams. * Chains together sequential vgmstreams, for data divided into separate sections or files * (like one part for intro and other for loop segments, which may even use different codecs). */ void render_vgmstream_segmented(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream) { int samples_written = 0; segmented_layout_data *data = vgmstream->layout_data; while (samples_written < sample_count) { int samples_to_do; int samples_this_block = data->segments[data->current_segment]->num_samples; if (vgmstream->loop_flag && vgmstream_do_loop(vgmstream)) { /* handle looping, finding loop segment */ int loop_segment = 0, samples = 0, loop_samples_skip = 0; while (samples < vgmstream->num_samples) { int32_t segment_samples = data->segments[loop_segment]->num_samples; if (vgmstream->loop_start_sample >= samples && vgmstream->loop_start_sample < samples + segment_samples) { loop_samples_skip = vgmstream->loop_start_sample - samples; break; /* loop_start falls within loop_segment's samples */ } samples += segment_samples; loop_segment++; } if (loop_segment == data->segment_count) { VGM_LOG("segmented_layout: can't find loop segment\n"); loop_segment = 0; } if (loop_samples_skip > 0) { VGM_LOG("segmented_layout: loop starts after %i samples\n", loop_samples_skip); //todo skip/fix, but probably won't happen } data->current_segment = loop_segment; reset_vgmstream(data->segments[data->current_segment]); vgmstream->samples_into_block = 0; continue; } samples_to_do = vgmstream_samples_to_do(samples_this_block, sample_count, vgmstream); if (samples_to_do > sample_count - samples_written) samples_to_do = sample_count - samples_written; /* detect segment change and restart */ if (samples_to_do == 0) { data->current_segment++; reset_vgmstream(data->segments[data->current_segment]); vgmstream->samples_into_block = 0; continue; } render_vgmstream(&buffer[samples_written*data->segments[data->current_segment]->channels], samples_to_do,data->segments[data->current_segment]); samples_written += samples_to_do; vgmstream->current_sample += samples_to_do; vgmstream->samples_into_block += samples_to_do; } }
int ReadPCM(void* context, uint8_t* pBuffer, int size, int *actualsize) { if (!context || !actualsize) return 1; VGMContext* ctx = (VGMContext*)context; render_vgmstream((sample*)pBuffer, size/(2*ctx->stream->channels), ctx->stream); *actualsize = size; ctx->pos += size; return 0; }
unsigned long __declspec(dllexport) DLL_Seek(long vgm, unsigned long timepos) { VGMSTREAM* song = (VGMSTREAM*)vgm; int16_t* buffer = new int16_t[576*song->channels]; long samples_to_do = (long)timepos * song->sample_rate / 1000L; if (samples_to_do < song->current_sample ) reset_vgmstream(song); else samples_to_do -= song->current_sample; while (samples_to_do > 0) { long l = samples_to_do>576?576:samples_to_do; render_vgmstream(buffer,l,song); samples_to_do -= l; } delete[] buffer; return timepos; }
int __stdcall XMP_Buffer(float* buffer, UINT32 bufsize) { int i,x,y; int adder = vgmstream->channels * (Decoder_Is_Using_Lame_Hack ? 2 : 1); /* ** Algorithm for correct playback. ** This is in fact a huge-ass hack which is terrible and crashes tracks with sample rates ** it doesn't like. We'll need to fix this later */ for (i=0;i<bufsize;i+=adder) { INT16 buf[16]; memset(buf,0,16 * 2); render_vgmstream(buf,vgmstream->channels,vgmstream); for (x=0;x<adder;x++) { for (y=0;y<(Decoder_Is_Using_Lame_Hack ? 2 : 1);y++) *(buffer + i + x + y) = (float)(buf[x]) / 22050; // This divide is required, audio is REALLY LOUD otherwise } } return bufsize; }
void decodeThread(void* arg) { debug("decode_buffer start\n"); stream_filename* strm_file = static_cast<stream_filename*>(arg); VGMSTREAM* vgmstream = strm_file->stream; std::string& filename = strm_file->filename; if (!vgmstream) return; const int channels = vgmstream->channels; const u32 stream_samples_amount = get_vgmstream_play_samples(1, 0, 0, vgmstream); u32 current_sample_pos = 0; stream_buffer* buffer = &playBuffer1; while (runThreads) { debug("decode_buffer wait produce\n"); // Wait for signal to make another stream svcWaitSynchronization(bufferReadyProduceRequest, U64_MAX); svcClearEvent(bufferReadyProduceRequest); u32 toget = max_samples; if (!vgmstream->loop_flag) { if (current_sample_pos >= stream_samples_amount) break; if (current_sample_pos + toget > stream_samples_amount) toget = stream_samples_amount - current_sample_pos; } debug("decode_buffer decode %d\n", toget); // TODO modify render_vgmstream to return not decode channel data sequentially in the buffer passed in. render_vgmstream(rawSampleBuffer, toget, vgmstream); debug("decode_buffer detangle\n"); // Detangle audio data... buffer->samples = toget; for (u32 i = 0; i < max_samples; i++) { for (int j = 0; j < channels; j++) { buffer->channels[j][i] = rawSampleBuffer[i * channels + j]; } } debug("decode_buffer signal consume\n"); // Ready to play svcSignalEvent(bufferReadyConsumeRequest); clearTopScreen(); print("\x1b[1;0HCurrently playing %s\nPress B to choose another song\nPress Start to exit", filename.c_str()); print("\x1b[29;0HPLAYING %.4lf %.4lf\n", (float)current_sample_pos / vgmstream->sample_rate, (float)stream_samples_amount / vgmstream->sample_rate); current_sample_pos += toget; // Flip buffers if (buffer == &playBuffer1) buffer = &playBuffer2; else buffer = &playBuffer1; debug("decode_buffer decode more\n"); } debug("decode_buffer done\n"); }
static int play_vgmstream(const char *filename, struct params *par) { int ret = 0; STREAMFILE *sf; VGMSTREAM *vgms; FILE *save_fps[4]; int loop_count; int64_t total_samples; size_t buffer_size; int64_t buffer_samples; int64_t fade_time_samples, fade_start; int time_total_min; double time_total_sec; int64_t s; int i; sf = open_stdio_streamfile(filename); if (!sf) { fprintf(stderr, "%s: cannot open file\n", filename); return -1; } sf->stream_index = par->stream_index; vgms = init_vgmstream_from_STREAMFILE(sf); close_streamfile(sf); if (!vgms) { fprintf(stderr, "%s: error opening stream\n", filename); return -1; } printf("Playing stream: %s\n", filename); /* Print metadata in verbose mode */ if (verbose) { char description[4096] = { '\0' }; describe_vgmstream(vgms, description, sizeof(description)); puts(description); putchar('\n'); } /* If the audio device hasn't been opened yet, then describe it */ if (!device) { ao_info *info = ao_driver_info(driver_id); printf("Audio device: %s\n", info->name); printf("Comment: %s\n", info->comment); putchar('\n'); } /* Stupid hack to hang onto a few low-numbered file descriptors * so that play_compressed_file() doesn't break, due to POSIX * wackiness like https://bugs.debian.org/590920 */ for (i = 0; i < 4; i++) save_fps[i] = fopen("/dev/null", "r"); ret = set_sample_format(vgms); if (ret) goto fail; loop_count = par->loop_count; if (vgms->loop_flag && loop_count < 0) { /* * Calculate how many loops are needed to achieve a minimum * playback time. Note: This calculation is derived from the * logic in get_vgmstream_play_samples(). */ double intro = (double)vgms->loop_start_sample / vgms->sample_rate; double loop = (double)(vgms->loop_end_sample - vgms->loop_start_sample) / vgms->sample_rate; double end = par->fade_time + par->fade_delay; if (loop < 1.0) loop = 1.0; loop_count = (int)((par->min_time - intro - end) / loop + 0.99); if (loop_count < 1) loop_count = 1; } total_samples = get_vgmstream_play_samples(loop_count, par->fade_time, par->fade_delay, vgms); { double total = (double)total_samples / vgms->sample_rate; time_total_min = (int)total / 60; time_total_sec = total - 60 * time_total_min; } /* Buffer size in bytes */ buffer_size = 1024 * buffer_size_kb; if (!buffer) { if (buffer_size_kb < 1) { fprintf(stderr, "Invalid buffer size '%d'\n", buffer_size_kb); return -1; } buffer = malloc(buffer_size); if (!buffer) goto fail; } buffer_samples = buffer_size / (vgms->channels * sizeof(sample)); fade_time_samples = (int64_t)(par->fade_time * vgms->sample_rate); fade_start = total_samples - fade_time_samples; if (fade_start < 0) fade_start = total_samples; for (s = 0; s < total_samples && !interrupted; s += buffer_samples) { int64_t buffer_used_samples = MIN(buffer_samples, total_samples - s); char *suffix = ""; render_vgmstream(buffer, buffer_used_samples, vgms); #ifdef LITTLE_ENDIAN_OUTPUT swap_samples_le(buffer, vgms->channels * buffer_used_samples); #endif if (vgms->loop_flag && fade_time_samples > 0 && s >= fade_start) { /* Got to do the fade-out ourselves :p */ int64_t b; for (b = 0; b < buffer_used_samples; b++) { double factor = 1.0 - (double)(s + b - fade_start) / fade_time_samples; int c; for (c = 0; c < vgms->channels; c++) buffer[vgms->channels * b + c] *= factor; } suffix = " (fading)"; } if (verbose && !out_filename) { double played = (double)s / vgms->sample_rate; double remain = (double)(total_samples - s) / vgms->sample_rate; int time_played_min = (int)played / 60; double time_played_sec = played - 60 * time_played_min; int time_remain_min = (int)remain / 60; double time_remain_sec = remain - 60 * time_remain_min; /* Time: 01:02.34 [08:57.66] of 10:00.00 */ printf("\rTime: %02d:%05.2f [%02d:%05.2f] of %02d:%05.2f%s ", time_played_min, time_played_sec, time_remain_min, time_remain_sec, time_total_min, time_total_sec, suffix); fflush(stdout); } if (!ao_play(device, (char *)buffer, buffer_used_samples * vgms->channels * sizeof(sample))) { fputs("\nAudio playback error\n", stderr); ao_close(device); device = NULL; ret = -1; break; } } if (verbose && !ret) { /* Clear time status line */ putchar('\r'); for (i = 0; i < 64; i++) putchar(' '); putchar('\r'); fflush(stdout); } if (out_filename && !ret) printf("Wrote %02d:%05.2f of audio to %s\n\n", time_total_min, time_total_sec, out_filename); if (interrupted) { fputs("Playback terminated.\n\n", stdout); ret = record_interrupt(); if (ret) fputs("Exiting...\n", stdout); } fail: close_vgmstream(vgms); for (i = 0; i < 4; i++) fclose(save_fps[i]); return ret; }