int opl3class::fm_init(unsigned int rate) { OPL3_Reset(&chip, rate); memset(command,0,sizeof(command)); memset(time, 0, sizeof(time)); memset(samples, 0, sizeof(samples)); counter = 0; lastwrite = 0; strpos = 0; endpos = 0; resampler = resampler_create(); if (!resampler) return 0; resampler_set_rate(resampler, 49716.0 / (double)rate); return 1; }
bool AudioThr::setParams( uchar realChn, uint realSRate, uchar chn, uint sRate ) { doSilence = -1.0; lastSpeed = playC.speed; realChannels = realChn; realSample_rate = realSRate; writer->modParam( "chn", ( channels = chn ? chn : realChannels ) ); writer->modParam( "rate", ( sample_rate = sRate ? sRate : realSRate ) ); bool paramsCorrected = false; if ( writer->processParams( ( sRate && chn ) ? NULL : ¶msCorrected ) ) //nie pozwala na korektę jeżeli są wymuszone parametry { if ( paramsCorrected ) { const uchar lastChn = channels; const uint lastSRate = sample_rate; channels = writer->getParam( "chn" ).toUInt(); sample_rate = writer->getParam( "rate" ).toUInt(); if ( ( !chn || channels == lastChn ) && ( !sRate || sample_rate == lastSRate ) ) QMPlay2Core.logInfo( tr( "Moduł" ) + " \"" + writer->name() + "\" " + tr( "ustawił parametry na" ) + ": " + QString::number( channels ) + " " + tr( "kanały" ) + ", " + QString::number( sample_rate ) + " " + tr( "Hz" ) ); else { QMPlay2Core.logError( tr( "Moduł" ) + " \"" + writer->name() + "\" " + tr( "wymaga zmiany jednego z wymuszonych parametrów, dźwięk wyłączony..." ) ); return false; } } if ( !resampler_create() ) { if ( paramsCorrected ) return false; channels = realChannels; sample_rate = realSample_rate; } foreach ( QMPlay2Extensions *vis, visualizations ) vis->visState( true, realChannels, realSample_rate ); foreach ( AudioFilter *filter, filters ) filter->setAudioParameters( realChannels, realSample_rate ); return true; } return false; }
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_clear(void * state) { size_t offset; memset(state, 0, usf_get_state_size()); offset = 4096 - (((uintptr_t)state) & 4095); USF_STATE_HELPER->offset_to_structure = offset; //USF_STATE->enablecompare = 0; //USF_STATE->enableFIFOfull = 0; //USF_STATE->enable_hle_audio = 0; // Constants, never written to USF_STATE->trunc_mode = 0xF3F; USF_STATE->round_mode = 0x33F; USF_STATE->ceil_mode = 0xB3F; USF_STATE->floor_mode = 0x73F; #ifdef DYNAREC USF_STATE->precomp_instr_size = sizeof(precomp_instr); #endif // USF_STATE->g_rom = 0; // USF_STATE->g_rom_size = 0; USF_STATE->save_state = calloc( 1, 0x80275c ); USF_STATE->save_state_size = 0x80275c; for (offset = 0; offset < 0x10000; offset += 4) { USF_STATE->EmptySpace[offset / 4] = (uint32_t)((offset << 16) | offset); } USF_STATE->resampler = resampler_create(); #ifdef DEBUG_INFO USF_STATE->debug_log = fopen("/tmp/lazyusf.log", "w"); #endif }
void AudioThr::run() { setPriority( QThread::HighestPriority ); QMutex emptyBufferMutex; bool paused = false; tmp_br = tmp_time = 0; #ifdef Q_OS_WIN canRefresh = false; #endif while ( !br ) { Packet packet; double delay = 0.0, audio_pts = 0.0; //"audio_pts" odporny na zerowanie przy przewijaniu Decoder *last_dec = dec; int bytes_consumed = -1; while ( !br && dec == last_dec ) { playC.aPackets.lock(); const bool hasAPackets = playC.aPackets.packetCount(); bool hasBufferedSamples = false; if ( playC.endOfStream && !hasAPackets ) foreach ( AudioFilter *filter, filters ) if ( filter->bufferedSamples() ) { hasBufferedSamples = true; break; } if ( playC.paused || ( !hasAPackets && !hasBufferedSamples ) || playC.waitForData ) { #ifdef Q_OS_WIN canRefresh = false; #endif tmp_br = tmp_time = 0; if ( playC.paused && !paused ) { doSilence = -1.0; writer->pause(); paused = true; emit pauseVisSig( paused ); } playC.aPackets.unlock(); if ( !playC.paused ) waiting = playC.fullBufferB = true; playC.emptyBufferCond.wait( &emptyBufferMutex, MUTEXWAIT_TIMEOUT ); emptyBufferMutex.unlock(); continue; } if ( paused ) { paused = false; emit pauseVisSig( paused ); } waiting = false; const bool flushAudio = playC.flushAudio; if ( !hasBufferedSamples && ( bytes_consumed < 0 || flushAudio ) ) packet = playC.aPackets.dequeue(); else if ( hasBufferedSamples ) packet.ts = audio_pts + playC.audio_last_delay + delay; //szacowanie czasu playC.aPackets.unlock(); playC.fullBufferB = true; mutex.lock(); if ( br ) { mutex.unlock(); break; } QByteArray decoded; if ( !hasBufferedSamples ) { bytes_consumed = dec->decode( packet, decoded, flushAudio ); tmp_br += bytes_consumed; } #ifndef Q_OS_WIN if ( tmp_time >= 1000.0 ) { emit playC.updateBitrate( round( ( tmp_br << 3 ) / tmp_time ), -1, -1.0 ); tmp_br = tmp_time = 0; } #endif delay = writer->getParam( "delay" ).toDouble(); foreach ( AudioFilter *filter, filters ) { if ( flushAudio ) filter->clearBuffers(); delay += filter->filter( decoded, hasBufferedSamples ); } if ( flushAudio ) playC.flushAudio = false; int decodedSize = decoded.size(); int decodedPos = 0; br2 = false; while ( decodedSize > 0 && !playC.paused && !br && !br2 ) { const double max_len = 0.02; //TODO: zrobić opcje? const int chunk = qMin( decodedSize, ( int )( ceil( realSample_rate * max_len ) * realChannels * sizeof( float ) ) ); const float vol = ( playC.muted || playC.vol == 0.0 ) ? 0.0 : playC.replayGain * ( playC.vol == 1.0 ? 1.0 : playC.vol * playC.vol ); QByteArray decodedChunk; if ( vol == 0.0 ) decodedChunk.fill( 0, chunk ); else decodedChunk = QByteArray::fromRawData( decoded.data() + decodedPos, chunk ); decodedPos += chunk; decodedSize -= chunk; playC.audio_last_delay = ( double )decodedChunk.size() / ( double )( sizeof( float ) * realChannels * realSample_rate ); if ( packet.ts.isValid() ) { audio_pts = playC.audio_current_pts = packet.ts - delay; if ( !playC.vThr ) { #ifdef Q_OS_WIN playC.chPos( playC.audio_current_pts, playC.flushAudio ); #else playC.chPos( playC.audio_current_pts ); #endif } } tmp_time += playC.audio_last_delay * 1000.0; packet.ts += playC.audio_last_delay; #ifdef Q_OS_WIN canRefresh = true; #endif if ( playC.skipAudioFrame <= 0.0 ) { const double speed = playC.speed; if ( speed != lastSpeed ) { resampler_create(); lastSpeed = speed; } if ( vol != 1.0 && vol > 0.0 ) { const int size = decodedChunk.size() / sizeof( float ); float *data = ( float * )decodedChunk.data(); for ( int i = 0 ; i < size ; ++i ) data[ i ] *= vol; } foreach ( QMPlay2Extensions *vis, visualizations ) vis->sendSoundData( decodedChunk ); QByteArray dataToWrite; if ( sndResampler.isOpen() ) sndResampler.convert( decodedChunk, dataToWrite ); else dataToWrite = decodedChunk; if ( doSilence >= 0.0 && vol > 0.0 ) { silenceChMutex.lock(); if ( doSilence >= 0.0 ) { float *data = ( float * )dataToWrite.data(); const int s = dataToWrite.size() / sizeof( float ); for ( int i = 0 ; i < s ; i += channels ) { for ( int j = 0 ; j < channels ; ++j ) data[ i+j ] *= doSilence; doSilence -= silence_step; if ( doSilence < 0.0 ) doSilence = 0.0; else if ( doSilence > 1.0 ) { doSilence = -1.0; break; } } } silenceChMutex.unlock(); } writer->write( dataToWrite ); } else playC.skipAudioFrame -= playC.audio_last_delay; } mutex.unlock(); if ( playC.flushAudio || packet.data.size() == bytes_consumed || ( !bytes_consumed && !decoded.size() ) ) { bytes_consumed = -1; packet = Packet(); } else if ( bytes_consumed != packet.data.size() ) packet.data.remove( 0, bytes_consumed ); } } }