예제 #1
0
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;
}
예제 #2
0
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 : &paramsCorrected ) ) //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;
}
예제 #3
0
	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);
		}
	}
예제 #4
0
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
}
예제 #5
0
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 );
		}
	}
}