Example #1
0
int jackDriverSampleRate( jack_nframes_t nframes, void *param )
{
	Object* __object = ( Object* )param;
	QString msg = QString("Jack SampleRate changed: the sample rate is now %1/sec").arg( QString::number( (int) nframes ) );
	__INFOLOG( msg );
	jack_server_sampleRate = nframes;
	return 0;
}
/**
 * Callback function for the JACK audio server to set the sample rate
 * #H2Core::jack_server_sampleRate and prints a message to
 * the #__INFOLOG, which has to be included via a Logger instance in
 * the provided @a param.
 *
 * It gets registered as a callback function of the JACK server in
 * JackAudioDriver::init() using _jack_set_sample_rate_callback()_.
 *
 * \param nframes New sample rate. The object has to be of type
 * _jack_nframes_t_, which is defined in the jack/types.h header.
 * \param param Object containing a Logger member to display the
 * change in the sample rate in its INFOLOG.
 *
 * @return 0 on success
 */
int jackDriverSampleRate( jack_nframes_t nframes, void* param ){
	// Used for logging.
	Object* __object = ( Object* )param;
	QString msg = QString("Jack SampleRate changed: the sample rate is now %1/sec").arg( QString::number( (int) nframes ) );
	// The __INFOLOG macro uses the Object *__object and not the
	// Object instance as INFOLOG does. It will call
	// __object->logger()->log( H2Core::Logger::Info, ..., msg )
	// (see object.h).
	__INFOLOG( msg );
	jack_server_sampleRate = nframes;
	return 0;
}
Example #3
0
void* diskWriterDriver_thread( void* param )
{

		Object* __object = ( Object* )param;
	DiskWriterDriver *pDriver = ( DiskWriterDriver* )param;
		EventQueue::get_instance()->push_event( EVENT_PROGRESS, 0 );
		pDriver->setBpm( Hydrogen::get_instance()->getSong()->__bpm );
		pDriver->audioEngine_process_checkBPMChanged();
	__INFOLOG( "DiskWriterDriver thread start" );

	// always rolling, no user interaction
	pDriver->m_transport.m_status = TransportInfo::ROLLING;

	SF_INFO soundInfo;
	soundInfo.samplerate = pDriver->m_nSampleRate;
//	soundInfo.frames = -1;//getNFrames();		///\todo: da terminare
	soundInfo.channels = 2;
	//default format
	int sfformat = 0x010000; //wav format (default)
	int bits = 0x0002; //16 bit PCM (default)
	//sf_format switch
	if( pDriver->m_sFilename.endsWith(".aiff") || pDriver->m_sFilename.endsWith(".AIFF") ){
		sfformat =  0x020000; //Apple/SGI AIFF format (big endian)
	}
	if( pDriver->m_sFilename.endsWith(".flac") || pDriver->m_sFilename.endsWith(".FLAC") ){
		sfformat =  0x170000; //FLAC lossless file format
	}
	if( ( pDriver->m_nSampleDepth == 8 ) && ( pDriver->m_sFilename.endsWith(".aiff") || pDriver->m_sFilename.endsWith(".AIFF") ) ){
		bits = 0x0001; //Signed 8 bit data works with aiff
	}
	if( ( pDriver->m_nSampleDepth == 8 ) && ( pDriver->m_sFilename.endsWith(".wav") || pDriver->m_sFilename.endsWith(".WAV") ) ){
		bits = 0x0005; //Unsigned 8 bit data needed for Microsoft WAV format
	}
	if( pDriver->m_nSampleDepth == 16 ){
		bits = 0x0002; //Signed 16 bit data
	}
	if( pDriver->m_nSampleDepth == 24 ){
		bits = 0x0003; //Signed 24 bit data
	}
	if( pDriver->m_nSampleDepth == 32 ){
		bits = 0x0004; ////Signed 32 bit data
	}

	soundInfo.format =  sfformat|bits;

//	#ifdef HAVE_OGGVORBIS

	//ogg vorbis option
	if( pDriver->m_sFilename.endsWith( ".ogg" ) | pDriver->m_sFilename.endsWith( ".OGG" ) )
		soundInfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;

//	#endif


///formats
//          SF_FORMAT_WAV          = 0x010000,     /* Microsoft WAV format (little endian). */
//          SF_FORMAT_AIFF         = 0x020000,     /* Apple/SGI AIFF format (big endian). */
//          SF_FORMAT_AU           = 0x030000,     /* Sun/NeXT AU format (big endian). */
//          SF_FORMAT_RAW          = 0x040000,     /* RAW PCM data. */
//          SF_FORMAT_PAF          = 0x050000,     /* Ensoniq PARIS file format. */
//          SF_FORMAT_SVX          = 0x060000,     /* Amiga IFF / SVX8 / SV16 format. */
//          SF_FORMAT_NIST         = 0x070000,     /* Sphere NIST format. */
//          SF_FORMAT_VOC          = 0x080000,     /* VOC files. */
//          SF_FORMAT_IRCAM        = 0x0A0000,     /* Berkeley/IRCAM/CARL */
//          SF_FORMAT_W64          = 0x0B0000,     /* Sonic Foundry's 64 bit RIFF/WAV */
//          SF_FORMAT_MAT4         = 0x0C0000,     /* Matlab (tm) V4.2 / GNU Octave 2.0 */
//          SF_FORMAT_MAT5         = 0x0D0000,     /* Matlab (tm) V5.0 / GNU Octave 2.1 */
//          SF_FORMAT_PVF          = 0x0E0000,     /* Portable Voice Format */
//          SF_FORMAT_XI           = 0x0F0000,     /* Fasttracker 2 Extended Instrument */
//          SF_FORMAT_HTK          = 0x100000,     /* HMM Tool Kit format */
//          SF_FORMAT_SDS          = 0x110000,     /* Midi Sample Dump Standard */
//          SF_FORMAT_AVR          = 0x120000,     /* Audio Visual Research */
//          SF_FORMAT_WAVEX        = 0x130000,     /* MS WAVE with WAVEFORMATEX */
//          SF_FORMAT_SD2          = 0x160000,     /* Sound Designer 2 */
//          SF_FORMAT_FLAC         = 0x170000,     /* FLAC lossless file format */
//          SF_FORMAT_CAF          = 0x180000,     /* Core Audio File format */
//	    SF_FORMAT_OGG
///bits
//          SF_FORMAT_PCM_S8       = 0x0001,       /* Signed 8 bit data */
//          SF_FORMAT_PCM_16       = 0x0002,       /* Signed 16 bit data */
//          SF_FORMAT_PCM_24       = 0x0003,       /* Signed 24 bit data */
//          SF_FORMAT_PCM_32       = 0x0004,       /* Signed 32 bit data */
///used for ogg
//          SF_FORMAT_VORBIS

	if ( !sf_format_check( &soundInfo ) ) {
		__ERRORLOG( "Error in soundInfo" );
		return 0;
	}


	SNDFILE* m_file = sf_open( pDriver->m_sFilename.toLocal8Bit(), SFM_WRITE, &soundInfo );

	float *pData = new float[ pDriver->m_nBufferSize * 2 ];	// always stereo

	float *pData_L = pDriver->m_pOut_L;
	float *pData_R = pDriver->m_pOut_R;


		Hydrogen* engine = Hydrogen::get_instance();

	std::vector<PatternList*> *pPatternColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector();
	int nColumns = pPatternColumns->size();

	int nPatternSize;
		int validBpm = engine->getSong()->__bpm;
		float oldBPM = 0;
		float ticksize = 0;
		for ( int patternposition = 0; patternposition < nColumns; ++patternposition ) {
				PatternList *pColumn = ( *pPatternColumns )[ patternposition ];
		if ( pColumn->size() != 0 ) {
			nPatternSize = pColumn->get( 0 )->get_length();
		} else {
			nPatternSize = MAX_NOTES;
				}

				ticksize = pDriver->m_nSampleRate * 60.0 /  engine->getSong()->__bpm / engine->getSong()->__resolution;
				// check pattern bpm if timeline bpm is in use
				Timeline* pTimeline = engine->getTimeline();
				if(Preferences::get_instance()->getUseTimelineBpm() ){
						if( pTimeline->m_timelinevector.size() >= 1 ){

								for ( int t = 0; t < pTimeline->m_timelinevector.size(); t++){
										if(pTimeline->m_timelinevector[t].m_htimelinebeat == patternposition &&
											pTimeline->m_timelinevector[t].m_htimelinebpm != validBpm){
												validBpm =  pTimeline->m_timelinevector[t].m_htimelinebpm;
										}

								}
						}
						pDriver->setBpm(validBpm);
						ticksize = pDriver->m_nSampleRate * 60.0 / validBpm / Hydrogen::get_instance()->getSong()->__resolution;
						pDriver->audioEngine_process_checkBPMChanged();
						engine->setPatternPos(patternposition);

						// delay needed time to calculate all rubberband samples
						if( Preferences::get_instance()->getRubberBandBatchMode() && validBpm != oldBPM ){
								EventQueue::get_instance()->push_event( EVENT_RECALCULATERUBBERBAND, -1);
								int sleepTime = Preferences::get_instance()->getRubberBandCalcTime()+1;
								while ((sleepTime = sleep(sleepTime)) > 0);
						}
						oldBPM = validBpm;

				}
				else
				{
						ticksize = pDriver->m_nSampleRate * 60.0 /  Hydrogen::get_instance()->getSong()->__bpm / Hydrogen::get_instance()->getSong()->__resolution;
						//pDriver->m_transport.m_nTickSize = ticksize;
				}


				 //here we have the pattern length in frames dependent from bpm and samplerate
				unsigned patternLengthInFrames = ticksize * nPatternSize;

				unsigned frameNumber = 0;
				int lastRun = 0;
				while ( frameNumber < patternLengthInFrames ) {

						int usedBuffer = pDriver->m_nBufferSize;

						//this will calculate the the size from -last- (end of pattern) used frame buffer,
						//which is mostly smaller than pDriver->m_nBufferSize
						if( patternLengthInFrames - frameNumber <  pDriver->m_nBufferSize ){
								lastRun = patternLengthInFrames - frameNumber;
								usedBuffer = lastRun;
						};

						frameNumber += usedBuffer;
						int ret = pDriver->m_processCallback( usedBuffer, NULL );

						for ( unsigned i = 0; i < usedBuffer; i++ ) {
								if(pData_L[i] > 1){
										pData[i * 2] = 1;
								}
								else if(pData_L[i] < -1){
										pData[i * 2] = -1;
								}else
								{
										pData[i * 2] = pData_L[i];
								}

								if(pData_R[i] > 1){
										pData[i * 2 + 1] = 1;
								}
								else if(pData_R[i] < -1){
										pData[i * 2 + 1] = -1;
								}else
								{
										pData[i * 2 + 1] = pData_R[i];
								}
						}
						int res = sf_writef_float( m_file, pData, usedBuffer );
						if ( res != ( int )usedBuffer ) {
								__ERRORLOG( "Error during sf_write_float" );
						}
				}

				// this progress bar methode is not exact but ok enough to give users a usable visible progress feedback
				float fPercent = ( float )(patternposition +1) / ( float )nColumns * 100.0;
				EventQueue::get_instance()->push_event( EVENT_PROGRESS, ( int )fPercent );
		}

	delete[] pData;
	pData = NULL;

	sf_close( m_file );

	__INFOLOG( "DiskWriterDriver thread end" );

	pthread_exit( NULL );

	return NULL;
}