void SPU_struct::KeyOn(int channel) { channel_struct &thischan = channels[channel]; thischan.init_resampler(); resampler_clear(thischan.resampler); resampler_set_quality(thischan.resampler, thischan.format == 3 ? RESAMPLER_QUALITY_BLEP : spuInterpolationMode(state)); adjust_channel_timer(&thischan); // LOG("Channel %d key on: vol = %d, datashift = %d, hold = %d, pan = %d, waveduty = %d, repeat = %d, format = %d, source address = %07X, timer = %04X, loop start = %04X, length = %06X, cpu->state->MMUARM7_REG[0x501] = %02X\n", channel, chan->vol, chan->datashift, chan->hold, chan->pan, chan->waveduty, chan->repeat, chan->format, chan->addr, chan->timer, chan->loopstart, chan->length, T1ReadByte(MMU->ARM7_REG, 0x501)); switch(thischan.format) { case 0: // 8-bit thischan.buf8 = (s8*)&state->MMU->MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & state->MMU->MMU_MASK[1][(thischan.addr >> 20) & 0xFF])]; // thischan.loopstart = thischan.loopstart << 2; // thischan.length = (thischan.length << 2) + thischan.loopstart; thischan.sampcnt = 0; break; case 1: // 16-bit thischan.buf16 = (s16 *)&state->MMU->MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & state->MMU->MMU_MASK[1][(thischan.addr >> 20) & 0xFF])]; // thischan.loopstart = thischan.loopstart << 1; // thischan.length = (thischan.length << 1) + thischan.loopstart; thischan.sampcnt = 0; break; case 2: // ADPCM { thischan.buf8 = (s8*)&state->MMU->MMU_MEM[1][(thischan.addr>>20)&0xFF][(thischan.addr & state->MMU->MMU_MASK[1][(thischan.addr >> 20) & 0xFF])]; thischan.pcm16b = (s16)((thischan.buf8[1] << 8) | thischan.buf8[0]); thischan.pcm16b_last = thischan.pcm16b; thischan.index = thischan.buf8[2] & 0x7F; thischan.lastsampcnt = 7; thischan.sampcnt = 8; thischan.loop_index = K_ADPCM_LOOPING_RECOVERY_INDEX; // thischan.loopstart = thischan.loopstart << 3; // thischan.length = (thischan.length << 3) + thischan.loopstart; break; } case 3: // PSG { thischan.x = 0x7FFF; break; } default: break; } if(thischan.format != 3) { if(thischan.double_totlength_shifted == 0) { printf("INFO: Stopping channel %d due to zero length\n",channel); thischan.status = CHANSTAT_STOPPED; } } thischan.double_totlength_shifted = (double)(thischan.totlength << format_shift[thischan.format]); }
USFPlayer(const std::string &fileName) { usf_state = new usf_loader_state; usf_state->emu_state = malloc( usf_get_state_size() ); usf_clear( usf_state->emu_state ); sample_rate = 0; char temp[fileName.length()+1]; strcpy(temp, fileName.c_str()); LOGD("Trying to load USF %s", string(temp)); if ( psf_load( temp, &psf_file_system, 0x21, usf_loader, usf_state, usf_info, usf_state, 1 ) < 0 ) throw player_exception(); usf_set_hle_audio(usf_state->emu_state, 1); PSFFile psf { fileName }; if(psf.valid()) { auto &tags = psf.tags(); int seconds = psf.songLength(); setMeta("composer", tags["artist"], "sub_title", tags["title"], "game", tags["game"], "format", "Nintendo 64", "length", seconds ); } usf_set_compare( usf_state->emu_state, usf_state->enable_compare ); usf_set_fifo_full( usf_state->emu_state, usf_state->enable_fifo_full ); const char *err = usf_render(usf_state->emu_state, 0, 0, &sample_rate); if(err) LOGD("ERROR %s", err); LOGD("######### RATE %d", sample_rate); resampler_init(); for(auto &r : resampler) { r = resampler_create(); resampler_set_quality(r, RESAMPLER_QUALITY_CUBIC); resampler_set_rate(r, (float)sample_rate / 44100.0); //resampler_set_rate(r, 44100.0 / (float)sample_rate); resampler_clear(r); } }
void usf_restart(void * state) { if ( USF_STATE->MemoryState ) { r4300_end(USF_STATE); if (USF_STATE->enable_trimming_mode) { bit_array_destroy(USF_STATE->barray_rom); bit_array_destroy(USF_STATE->barray_ram_read); bit_array_destroy(USF_STATE->barray_ram_written_first); USF_STATE->barray_rom = 0; USF_STATE->barray_ram_read = 0; USF_STATE->barray_ram_written_first = 0; } USF_STATE->MemoryState = 0; } USF_STATE->samples_in_buffer = 0; USF_STATE->samples_in_buffer_2 = 0; resampler_clear(USF_STATE->resampler); }
const char * usf_render_resampled(void * state, int16_t * buffer, size_t count, int32_t sample_rate) { if ( !buffer ) { unsigned long samples_buffered = resampler_get_sample_count( USF_STATE->resampler ); resampler_clear(USF_STATE->resampler); if (samples_buffered) { unsigned long samples_to_remove = samples_buffered; if (samples_to_remove > count) samples_to_remove = count; while (samples_to_remove--) resampler_remove_sample(USF_STATE->resampler); if (!count) return 0; } count = (size_t)((uint64_t)count * USF_STATE->SampleRate / sample_rate); if (count > USF_STATE->samples_in_buffer_2) { count -= USF_STATE->samples_in_buffer_2; USF_STATE->samples_in_buffer_2 = 0; } else if (count) { USF_STATE->samples_in_buffer_2 -= count; memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + 8192 - USF_STATE->samples_in_buffer_2 * 2, USF_STATE->samples_in_buffer_2 * sizeof(short) * 2); return 0; } return usf_render(state, buffer, count, NULL); } while ( count ) { const char * err; while ( USF_STATE->samples_in_buffer_2 && resampler_get_free_count(USF_STATE->resampler) ) { int i = 0, j = resampler_get_free_count(USF_STATE->resampler); if (j > USF_STATE->samples_in_buffer_2) j = (int)USF_STATE->samples_in_buffer_2; for (i = 0; i < j; ++i) { resampler_write_sample(USF_STATE->resampler, USF_STATE->samplebuf2[i*2], USF_STATE->samplebuf2[i*2+1]); } memmove(USF_STATE->samplebuf2, USF_STATE->samplebuf2 + i * 2, (USF_STATE->samples_in_buffer_2 - i) * sizeof(short) * 2); USF_STATE->samples_in_buffer_2 -= i; } while ( count && resampler_get_sample_count(USF_STATE->resampler) ) { resampler_get_sample(USF_STATE->resampler, buffer, buffer + 1); resampler_remove_sample(USF_STATE->resampler); buffer += 2; --count; } if (!count) break; if (USF_STATE->samples_in_buffer_2) continue; err = usf_render(state, USF_STATE->samplebuf2, 4096, 0); if (err) return err; USF_STATE->samples_in_buffer_2 = 4096; resampler_set_rate(USF_STATE->resampler, (float)USF_STATE->SampleRate / (float)sample_rate); } return 0; }