1 /*
2  * SampleBuffer.cpp - container-class SampleBuffer
3  *
4  * Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
5  *
6  * This file is part of LMMS - https://lmms.io
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public
19  * License along with this program (see COPYING); if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301 USA.
22  *
23  */
24 
25 #include "SampleBuffer.h"
26 
27 
28 #include <QBuffer>
29 #include <QFile>
30 #include <QFileInfo>
31 #include <QMessageBox>
32 #include <QPainter>
33 
34 
35 #include <sndfile.h>
36 
37 #define OV_EXCLUDE_STATIC_CALLBACKS
38 #ifdef LMMS_HAVE_OGGVORBIS
39 #include <vorbis/vorbisfile.h>
40 #endif
41 
42 #ifdef LMMS_HAVE_FLAC_STREAM_ENCODER_H
43 #include <FLAC/stream_encoder.h>
44 #endif
45 
46 #ifdef LMMS_HAVE_FLAC_STREAM_DECODER_H
47 #include <FLAC/stream_decoder.h>
48 #endif
49 
50 
51 #include "base64.h"
52 #include "ConfigManager.h"
53 #include "DrumSynth.h"
54 #include "endian_handling.h"
55 #include "Engine.h"
56 #include "GuiApplication.h"
57 #include "Mixer.h"
58 
59 #include "FileDialog.h"
60 
61 
SampleBuffer(const QString & _audio_file,bool _is_base64_data)62 SampleBuffer::SampleBuffer( const QString & _audio_file,
63 							bool _is_base64_data ) :
64 	m_audioFile( ( _is_base64_data == true ) ? "" : _audio_file ),
65 	m_origData( NULL ),
66 	m_origFrames( 0 ),
67 	m_data( NULL ),
68 	m_frames( 0 ),
69 	m_startFrame( 0 ),
70 	m_endFrame( 0 ),
71 	m_loopStartFrame( 0 ),
72 	m_loopEndFrame( 0 ),
73 	m_amplification( 1.0f ),
74 	m_reversed( false ),
75 	m_frequency( BaseFreq ),
76 	m_sampleRate( mixerSampleRate () )
77 {
78 	if( _is_base64_data == true )
79 	{
80 		loadFromBase64( _audio_file );
81 	}
82 	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
83 	update();
84 }
85 
86 
87 
88 
SampleBuffer(const sampleFrame * _data,const f_cnt_t _frames)89 SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
90 	m_audioFile( "" ),
91 	m_origData( NULL ),
92 	m_origFrames( 0 ),
93 	m_data( NULL ),
94 	m_frames( 0 ),
95 	m_startFrame( 0 ),
96 	m_endFrame( 0 ),
97 	m_loopStartFrame( 0 ),
98 	m_loopEndFrame( 0 ),
99 	m_amplification( 1.0f ),
100 	m_reversed( false ),
101 	m_frequency( BaseFreq ),
102 	m_sampleRate( mixerSampleRate () )
103 {
104 	if( _frames > 0 )
105 	{
106 		m_origData = MM_ALLOC( sampleFrame, _frames );
107 		memcpy( m_origData, _data, _frames * BYTES_PER_FRAME );
108 		m_origFrames = _frames;
109 	}
110 	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
111 	update();
112 }
113 
114 
115 
116 
SampleBuffer(const f_cnt_t _frames)117 SampleBuffer::SampleBuffer( const f_cnt_t _frames ) :
118 	m_audioFile( "" ),
119 	m_origData( NULL ),
120 	m_origFrames( 0 ),
121 	m_data( NULL ),
122 	m_frames( 0 ),
123 	m_startFrame( 0 ),
124 	m_endFrame( 0 ),
125 	m_loopStartFrame( 0 ),
126 	m_loopEndFrame( 0 ),
127 	m_amplification( 1.0f ),
128 	m_reversed( false ),
129 	m_frequency( BaseFreq ),
130 	m_sampleRate( mixerSampleRate () )
131 {
132 	if( _frames > 0 )
133 	{
134 		m_origData = MM_ALLOC( sampleFrame, _frames );
135 		memset( m_origData, 0, _frames * BYTES_PER_FRAME );
136 		m_origFrames = _frames;
137 	}
138 	connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
139 	update();
140 }
141 
142 
143 
144 
~SampleBuffer()145 SampleBuffer::~SampleBuffer()
146 {
147 	MM_FREE( m_origData );
148 	MM_FREE( m_data );
149 }
150 
151 
152 
sampleRateChanged()153 void SampleBuffer::sampleRateChanged()
154 {
155 	update( true );
156 }
157 
mixerSampleRate()158 sample_rate_t SampleBuffer::mixerSampleRate()
159 {
160 	return Engine::mixer()->processingSampleRate();
161 }
162 
163 
update(bool _keep_settings)164 void SampleBuffer::update( bool _keep_settings )
165 {
166 	const bool lock = ( m_data != NULL );
167 	if( lock )
168 	{
169 		Engine::mixer()->requestChangeInModel();
170 		m_varLock.lockForWrite();
171 		MM_FREE( m_data );
172 	}
173 
174 	// File size and sample length limits
175 	const int fileSizeMax = 300; // MB
176 	const int sampleLengthMax = 90; // Minutes
177 
178 	bool fileLoadError = false;
179 	if( m_audioFile.isEmpty() && m_origData != NULL && m_origFrames > 0 )
180 	{
181 		// TODO: reverse- and amplification-property is not covered
182 		// by following code...
183 		m_data = MM_ALLOC( sampleFrame, m_origFrames );
184 		memcpy( m_data, m_origData, m_origFrames * BYTES_PER_FRAME );
185 		if( _keep_settings == false )
186 		{
187 			m_frames = m_origFrames;
188 			m_loopStartFrame = m_startFrame = 0;
189 			m_loopEndFrame = m_endFrame = m_frames;
190 		}
191 	}
192 	else if( !m_audioFile.isEmpty() )
193 	{
194 		QString file = tryToMakeAbsolute( m_audioFile );
195 		int_sample_t * buf = NULL;
196 		sample_t * fbuf = NULL;
197 		ch_cnt_t channels = DEFAULT_CHANNELS;
198 		sample_rate_t samplerate = mixerSampleRate();
199 		m_frames = 0;
200 
201 		const QFileInfo fileInfo( file );
202 		if( fileInfo.size() > fileSizeMax * 1024 * 1024 )
203 		{
204 			fileLoadError = true;
205 		}
206 		else
207 		{
208 			// Use QFile to handle unicode file names on Windows
209 			QFile f(file);
210 			f.open(QIODevice::ReadOnly);
211 			SNDFILE * snd_file;
212 			SF_INFO sf_info;
213 			sf_info.format = 0;
214 			if( ( snd_file = sf_open_fd( f.handle(), SFM_READ, &sf_info, false ) ) != NULL )
215 			{
216 				f_cnt_t frames = sf_info.frames;
217 				int rate = sf_info.samplerate;
218 				if( frames / rate > sampleLengthMax * 60 )
219 				{
220 					fileLoadError = true;
221 				}
222 				sf_close( snd_file );
223 			}
224 			f.close();
225 		}
226 
227 		if( !fileLoadError )
228 		{
229 #ifdef LMMS_HAVE_OGGVORBIS
230 			// workaround for a bug in libsndfile or our libsndfile decoder
231 			// causing some OGG files to be distorted -> try with OGG Vorbis
232 			// decoder first if filename extension matches "ogg"
233 			if( m_frames == 0 && fileInfo.suffix() == "ogg" )
234 			{
235 				m_frames = decodeSampleOGGVorbis( file, buf, channels, samplerate );
236 			}
237 #endif
238 			if( m_frames == 0 )
239 			{
240 				m_frames = decodeSampleSF( file, fbuf, channels,
241 									samplerate );
242 			}
243 #ifdef LMMS_HAVE_OGGVORBIS
244 			if( m_frames == 0 )
245 			{
246 				m_frames = decodeSampleOGGVorbis( file, buf, channels,
247 									samplerate );
248 			}
249 #endif
250 			if( m_frames == 0 )
251 			{
252 				m_frames = decodeSampleDS( file, buf, channels,
253 									samplerate );
254 			}
255 		}
256 
257 		if ( m_frames == 0 || fileLoadError )  // if still no frames, bail
258 		{
259 			// sample couldn't be decoded, create buffer containing
260 			// one sample-frame
261 			m_data = MM_ALLOC( sampleFrame, 1 );
262 			memset( m_data, 0, sizeof( *m_data ) );
263 			m_frames = 1;
264 			m_loopStartFrame = m_startFrame = 0;
265 			m_loopEndFrame = m_endFrame = 1;
266 		}
267 		else // otherwise normalize sample rate
268 		{
269 			normalizeSampleRate( samplerate, _keep_settings );
270 		}
271 	}
272 	else
273 	{
274 		// neither an audio-file nor a buffer to copy from, so create
275 		// buffer containing one sample-frame
276 		m_data = MM_ALLOC( sampleFrame, 1 );
277 		memset( m_data, 0, sizeof( *m_data ) );
278 		m_frames = 1;
279 		m_loopStartFrame = m_startFrame = 0;
280 		m_loopEndFrame = m_endFrame = 1;
281 	}
282 
283 	if( lock )
284 	{
285 		m_varLock.unlock();
286 		Engine::mixer()->doneChangeInModel();
287 	}
288 
289 	emit sampleUpdated();
290 
291 	if( fileLoadError )
292 	{
293 		QString title = tr( "Fail to open file" );
294 		QString message = tr( "Audio files are limited to %1 MB "
295 				"in size and %2 minutes of playing time"
296 				).arg( fileSizeMax ).arg( sampleLengthMax );
297 		if( gui )
298 		{
299 			QMessageBox::information( NULL,
300 				title, message,	QMessageBox::Ok );
301 		}
302 		else
303 		{
304 			fprintf( stderr, "%s\n", message.toUtf8().constData() );
305 		}
306 	}
307 }
308 
309 
convertIntToFloat(int_sample_t * & _ibuf,f_cnt_t _frames,int _channels)310 void SampleBuffer::convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels)
311 {
312 	// following code transforms int-samples into
313 	// float-samples and does amplifying & reversing
314 	const float fac = 1 / OUTPUT_SAMPLE_MULTIPLIER;
315 	m_data = MM_ALLOC( sampleFrame, _frames );
316 	const int ch = ( _channels > 1 ) ? 1 : 0;
317 
318 	// if reversing is on, we also reverse when
319 	// scaling
320 	if( m_reversed )
321 	{
322 		int idx = ( _frames - 1 ) * _channels;
323 		for( f_cnt_t frame = 0; frame < _frames;
324 						++frame )
325 		{
326 			m_data[frame][0] = _ibuf[idx+0] * fac;
327 			m_data[frame][1] = _ibuf[idx+ch] * fac;
328 			idx -= _channels;
329 		}
330 	}
331 	else
332 	{
333 		int idx = 0;
334 		for( f_cnt_t frame = 0; frame < _frames;
335 						++frame )
336 		{
337 			m_data[frame][0] = _ibuf[idx+0] * fac;
338 			m_data[frame][1] = _ibuf[idx+ch] * fac;
339 			idx += _channels;
340 		}
341 	}
342 
343 	delete[] _ibuf;
344 }
345 
directFloatWrite(sample_t * & _fbuf,f_cnt_t _frames,int _channels)346 void SampleBuffer::directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels)
347 
348 {
349 
350 	m_data = MM_ALLOC( sampleFrame, _frames );
351 	const int ch = ( _channels > 1 ) ? 1 : 0;
352 
353 	// if reversing is on, we also reverse when
354 	// scaling
355 	if( m_reversed )
356 	{
357 		int idx = ( _frames - 1 ) * _channels;
358 		for( f_cnt_t frame = 0; frame < _frames;
359 						++frame )
360 		{
361 			m_data[frame][0] = _fbuf[idx+0];
362 			m_data[frame][1] = _fbuf[idx+ch];
363 			idx -= _channels;
364 		}
365 	}
366 	else
367 	{
368 		int idx = 0;
369 		for( f_cnt_t frame = 0; frame < _frames;
370 						++frame )
371 		{
372 			m_data[frame][0] = _fbuf[idx+0];
373 			m_data[frame][1] = _fbuf[idx+ch];
374 			idx += _channels;
375 		}
376 	}
377 
378 	delete[] _fbuf;
379 }
380 
381 
normalizeSampleRate(const sample_rate_t _src_sr,bool _keep_settings)382 void SampleBuffer::normalizeSampleRate( const sample_rate_t _src_sr,
383 							bool _keep_settings )
384 {
385 	const sample_rate_t old_rate = m_sampleRate;
386 	// do samplerate-conversion to our default-samplerate
387 	if( _src_sr != mixerSampleRate() )
388 	{
389 		SampleBuffer * resampled = resample( _src_sr,
390 					mixerSampleRate() );
391 
392 		m_sampleRate = mixerSampleRate();
393 		MM_FREE( m_data );
394 		m_frames = resampled->frames();
395 		m_data = MM_ALLOC( sampleFrame, m_frames );
396 		memcpy( m_data, resampled->data(), m_frames *
397 							sizeof( sampleFrame ) );
398 		delete resampled;
399 	}
400 
401 	if( _keep_settings == false )
402 	{
403 		// update frame-variables
404 		m_loopStartFrame = m_startFrame = 0;
405 		m_loopEndFrame = m_endFrame = m_frames;
406 	}
407 	else if( old_rate != mixerSampleRate() )
408 	{
409 		auto old_rate_to_new_rate_ratio = static_cast<float>(mixerSampleRate()) / old_rate;
410 
411 		m_startFrame = qBound(0, f_cnt_t(m_startFrame*old_rate_to_new_rate_ratio), m_frames);
412 		m_endFrame = qBound(m_startFrame, f_cnt_t(m_endFrame*old_rate_to_new_rate_ratio), m_frames);
413 		m_loopStartFrame = qBound(0, f_cnt_t(m_loopStartFrame*old_rate_to_new_rate_ratio), m_frames);
414 		m_loopEndFrame = qBound(m_loopStartFrame, f_cnt_t(m_loopEndFrame*old_rate_to_new_rate_ratio), m_frames);
415 		m_sampleRate = mixerSampleRate();
416 	}
417 }
418 
419 
420 
421 
decodeSampleSF(QString _f,sample_t * & _buf,ch_cnt_t & _channels,sample_rate_t & _samplerate)422 f_cnt_t SampleBuffer::decodeSampleSF(QString _f,
423 					sample_t * & _buf,
424 					ch_cnt_t & _channels,
425 					sample_rate_t & _samplerate )
426 {
427 	SNDFILE * snd_file;
428 	SF_INFO sf_info;
429 	sf_info.format = 0;
430 	f_cnt_t frames = 0;
431 	bool sf_rr = false;
432 
433 
434 	// Use QFile to handle unicode file names on Windows
435 	QFile f(_f);
436 	f.open(QIODevice::ReadOnly);
437 	if( ( snd_file = sf_open_fd( f.handle(), SFM_READ, &sf_info, false ) ) != NULL )
438 	{
439 		frames = sf_info.frames;
440 
441 		_buf = new sample_t[sf_info.channels * frames];
442 		sf_rr = sf_read_float( snd_file, _buf, sf_info.channels * frames );
443 
444 		if( sf_rr < sf_info.channels * frames )
445 		{
446 #ifdef DEBUG_LMMS
447 			qDebug( "SampleBuffer::decodeSampleSF(): could not read"
448 				" sample %s: %s", _f, sf_strerror( NULL ) );
449 #endif
450 		}
451 		_channels = sf_info.channels;
452 		_samplerate = sf_info.samplerate;
453 
454 		sf_close( snd_file );
455 	}
456 	else
457 	{
458 #ifdef DEBUG_LMMS
459 		qDebug( "SampleBuffer::decodeSampleSF(): could not load "
460 				"sample %s: %s", _f, sf_strerror( NULL ) );
461 #endif
462 	}
463 	f.close();
464 
465 	//write down either directly or convert i->f depending on file type
466 
467 	if ( frames > 0 && _buf != NULL )
468 	{
469 		directFloatWrite ( _buf, frames, _channels);
470 	}
471 
472 	return frames;
473 }
474 
475 
476 
477 
478 #ifdef LMMS_HAVE_OGGVORBIS
479 
480 // callback-functions for reading ogg-file
481 
qfileReadCallback(void * _ptr,size_t _size,size_t _n,void * _udata)482 size_t qfileReadCallback( void * _ptr, size_t _size, size_t _n, void * _udata )
483 {
484 	return static_cast<QFile *>( _udata )->read( (char*) _ptr,
485 								_size * _n );
486 }
487 
488 
489 
490 
qfileSeekCallback(void * _udata,ogg_int64_t _offset,int _whence)491 int qfileSeekCallback( void * _udata, ogg_int64_t _offset, int _whence )
492 {
493 	QFile * f = static_cast<QFile *>( _udata );
494 
495 	if( _whence == SEEK_CUR )
496 	{
497 		f->seek( f->pos() + _offset );
498 	}
499 	else if( _whence == SEEK_END )
500 	{
501 		f->seek( f->size() + _offset );
502 	}
503 	else
504 	{
505 		f->seek( _offset );
506 	}
507 	return 0;
508 }
509 
510 
511 
512 
qfileCloseCallback(void * _udata)513 int qfileCloseCallback( void * _udata )
514 {
515 	delete static_cast<QFile *>( _udata );
516 	return 0;
517 }
518 
519 
520 
521 
qfileTellCallback(void * _udata)522 long qfileTellCallback( void * _udata )
523 {
524 	return static_cast<QFile *>( _udata )->pos();
525 }
526 
527 
528 
529 
decodeSampleOGGVorbis(QString _f,int_sample_t * & _buf,ch_cnt_t & _channels,sample_rate_t & _samplerate)530 f_cnt_t SampleBuffer::decodeSampleOGGVorbis( QString _f,
531 						int_sample_t * & _buf,
532 						ch_cnt_t & _channels,
533 						sample_rate_t & _samplerate )
534 {
535 	static ov_callbacks callbacks =
536 	{
537 		qfileReadCallback,
538 		qfileSeekCallback,
539 		qfileCloseCallback,
540 		qfileTellCallback
541 	} ;
542 
543 	OggVorbis_File vf;
544 
545 	f_cnt_t frames = 0;
546 
547 	QFile * f = new QFile( _f );
548 	if( f->open( QFile::ReadOnly ) == false )
549 	{
550 		delete f;
551 		return 0;
552 	}
553 
554 	int err = ov_open_callbacks( f, &vf, NULL, 0, callbacks );
555 
556 	if( err < 0 )
557 	{
558 		switch( err )
559 		{
560 			case OV_EREAD:
561 				printf( "SampleBuffer::decodeSampleOGGVorbis():"
562 						" media read error\n" );
563 				break;
564 			case OV_ENOTVORBIS:
565 /*				printf( "SampleBuffer::decodeSampleOGGVorbis():"
566 					" not an Ogg Vorbis file\n" );*/
567 				break;
568 			case OV_EVERSION:
569 				printf( "SampleBuffer::decodeSampleOGGVorbis():"
570 						" vorbis version mismatch\n" );
571 				break;
572 			case OV_EBADHEADER:
573 				printf( "SampleBuffer::decodeSampleOGGVorbis():"
574 					" invalid Vorbis bitstream header\n" );
575 				break;
576 			case OV_EFAULT:
577 				printf( "SampleBuffer::decodeSampleOgg(): "
578 					"internal logic fault\n" );
579 				break;
580 		}
581 		delete f;
582 		return 0;
583 	}
584 
585 	ov_pcm_seek( &vf, 0 );
586 
587    	_channels = ov_info( &vf, -1 )->channels;
588    	_samplerate = ov_info( &vf, -1 )->rate;
589 
590 	ogg_int64_t total = ov_pcm_total( &vf, -1 );
591 
592 	_buf = new int_sample_t[total * _channels];
593 	int bitstream = 0;
594 	long bytes_read = 0;
595 
596 	do
597 	{
598 		bytes_read = ov_read( &vf, (char *) &_buf[frames * _channels],
599 					( total - frames ) * _channels *
600 							BYTES_PER_INT_SAMPLE,
601 					isLittleEndian() ? 0 : 1,
602 					BYTES_PER_INT_SAMPLE, 1, &bitstream );
603 		if( bytes_read < 0 )
604 		{
605 			break;
606 		}
607 		frames += bytes_read / ( _channels * BYTES_PER_INT_SAMPLE );
608 	}
609 	while( bytes_read != 0 && bitstream == 0 );
610 
611 	ov_clear( &vf );
612 	// if buffer isn't empty, convert it to float and write it down
613 
614 	if ( frames > 0 && _buf != NULL )
615 	{
616 		convertIntToFloat ( _buf, frames, _channels);
617 	}
618 
619 	return frames;
620 }
621 #endif
622 
623 
624 
625 
decodeSampleDS(QString _f,int_sample_t * & _buf,ch_cnt_t & _channels,sample_rate_t & _samplerate)626 f_cnt_t SampleBuffer::decodeSampleDS( QString _f,
627 						int_sample_t * & _buf,
628 						ch_cnt_t & _channels,
629 						sample_rate_t & _samplerate )
630 {
631 	DrumSynth ds;
632 	f_cnt_t frames = ds.GetDSFileSamples( _f, _buf, _channels, _samplerate );
633 
634 	if ( frames > 0 && _buf != NULL )
635 	{
636 		convertIntToFloat ( _buf, frames, _channels);
637 	}
638 
639 	return frames;
640 
641 }
642 
643 
644 
645 
play(sampleFrame * _ab,handleState * _state,const fpp_t _frames,const float _freq,const LoopMode _loopmode)646 bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
647 					const fpp_t _frames,
648 					const float _freq,
649 					const LoopMode _loopmode )
650 {
651 	f_cnt_t startFrame = m_startFrame;
652 	f_cnt_t endFrame = m_endFrame;
653 	f_cnt_t loopStartFrame = m_loopStartFrame;
654 	f_cnt_t loopEndFrame = m_loopEndFrame;
655 
656 	if( endFrame == 0 || _frames == 0 )
657 	{
658 		return false;
659 	}
660 
661 	// variable for determining if we should currently be playing backwards in a ping-pong loop
662 	bool is_backwards = _state->isBackwards();
663 
664 	const double freq_factor = (double) _freq / (double) m_frequency *
665 		m_sampleRate / Engine::mixer()->processingSampleRate();
666 
667 	// calculate how many frames we have in requested pitch
668 	const f_cnt_t total_frames_for_current_pitch = static_cast<f_cnt_t>( (
669 						endFrame - startFrame ) /
670 								freq_factor );
671 
672 	if( total_frames_for_current_pitch == 0 )
673 	{
674 		return false;
675 	}
676 
677 
678 	// this holds the index of the first frame to play
679 	f_cnt_t play_frame = qMax(_state->m_frameIndex, startFrame);
680 
681 	if( _loopmode == LoopOff )
682 	{
683 		if( play_frame >= endFrame || ( endFrame - play_frame ) / freq_factor == 0 )
684 		{
685 			// the sample is done being played
686 			return false;
687 		}
688 	}
689 	else if( _loopmode == LoopOn )
690 	{
691 		play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
692 	}
693 	else
694 	{
695 		play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
696 	}
697 
698 	f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpolationMode() ];
699 
700 	sampleFrame * tmp = NULL;
701 
702 	// check whether we have to change pitch...
703 	if( freq_factor != 1.0 || _state->m_varyingPitch )
704 	{
705 		SRC_DATA src_data;
706 		// Generate output
707 		src_data.data_in =
708 			getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards,
709 			loopStartFrame, loopEndFrame, endFrame )[0];
710 		src_data.data_out = _ab[0];
711 		src_data.input_frames = fragment_size;
712 		src_data.output_frames = _frames;
713 		src_data.src_ratio = 1.0 / freq_factor;
714 		src_data.end_of_input = 0;
715 		int error = src_process( _state->m_resamplingData,
716 								&src_data );
717 		if( error )
718 		{
719 			printf( "SampleBuffer: error while resampling: %s\n",
720 							src_strerror( error ) );
721 		}
722 		if( src_data.output_frames_gen > _frames )
723 		{
724 			printf( "SampleBuffer: not enough frames: %ld / %d\n",
725 					src_data.output_frames_gen, _frames );
726 		}
727 		// Advance
728 		switch( _loopmode )
729 		{
730 			case LoopOff:
731 				play_frame += src_data.input_frames_used;
732 				break;
733 			case LoopOn:
734 				play_frame += src_data.input_frames_used;
735 				play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
736 				break;
737 			case LoopPingPong:
738 			{
739 				f_cnt_t left = src_data.input_frames_used;
740 				if( _state->isBackwards() )
741 				{
742 					play_frame -= src_data.input_frames_used;
743 					if( play_frame < loopStartFrame )
744 					{
745 						left -= ( loopStartFrame - play_frame );
746 						play_frame = loopStartFrame;
747 					}
748 					else left = 0;
749 				}
750 				play_frame += left;
751 				play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame  );
752 				break;
753 			}
754 		}
755 	}
756 	else
757 	{
758 		// we don't have to pitch, so we just copy the sample-data
759 		// as is into pitched-copy-buffer
760 
761 		// Generate output
762 		memcpy( _ab,
763 			getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards,
764 						loopStartFrame, loopEndFrame, endFrame ),
765 						_frames * BYTES_PER_FRAME );
766 		// Advance
767 		switch( _loopmode )
768 		{
769 			case LoopOff:
770 				play_frame += _frames;
771 				break;
772 			case LoopOn:
773 				play_frame += _frames;
774 				play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame  );
775 				break;
776 			case LoopPingPong:
777 			{
778 				f_cnt_t left = _frames;
779 				if( _state->isBackwards() )
780 				{
781 					play_frame -= _frames;
782 					if( play_frame < loopStartFrame )
783 					{
784 						left -= ( loopStartFrame - play_frame );
785 						play_frame = loopStartFrame;
786 					}
787 					else left = 0;
788 				}
789 				play_frame += left;
790 				play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame  );
791 				break;
792 			}
793 		}
794 	}
795 
796 	if( tmp != NULL )
797 	{
798 		MM_FREE( tmp );
799 	}
800 
801 	_state->setBackwards( is_backwards );
802 	_state->setFrameIndex( play_frame );
803 
804 	for( fpp_t i = 0; i < _frames; ++i )
805 	{
806 		_ab[i][0] *= m_amplification;
807 		_ab[i][1] *= m_amplification;
808 	}
809 
810 	return true;
811 }
812 
813 
814 
815 
getSampleFragment(f_cnt_t _index,f_cnt_t _frames,LoopMode _loopmode,sampleFrame ** _tmp,bool * _backwards,f_cnt_t _loopstart,f_cnt_t _loopend,f_cnt_t _end) const816 sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _index,
817 		f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards,
818 		f_cnt_t _loopstart, f_cnt_t _loopend, f_cnt_t _end ) const
819 {
820 	if( _loopmode == LoopOff )
821 	{
822 		if( _index + _frames <= _end )
823 		{
824 			return m_data + _index;
825 		}
826 	}
827 	else if( _loopmode == LoopOn )
828 	{
829 		if( _index + _frames <= _loopend )
830 		{
831 			return m_data + _index;
832 		}
833 	}
834 	else
835 	{
836 		if( ! *_backwards && _index + _frames < _loopend )
837 		{
838 			return m_data + _index;
839 		}
840 	}
841 
842 	*_tmp = MM_ALLOC( sampleFrame, _frames );
843 
844 	if( _loopmode == LoopOff )
845 	{
846 		f_cnt_t available = _end - _index;
847 		memcpy( *_tmp, m_data + _index, available * BYTES_PER_FRAME );
848 		memset( *_tmp + available, 0, ( _frames - available ) *
849 							BYTES_PER_FRAME );
850 	}
851 	else if( _loopmode == LoopOn )
852 	{
853 		f_cnt_t copied = qMin( _frames, _loopend - _index );
854 		memcpy( *_tmp, m_data + _index, copied * BYTES_PER_FRAME );
855 		f_cnt_t loop_frames = _loopend - _loopstart;
856 		while( copied < _frames )
857 		{
858 			f_cnt_t todo = qMin( _frames - copied, loop_frames );
859 			memcpy( *_tmp + copied, m_data + _loopstart, todo * BYTES_PER_FRAME );
860 			copied += todo;
861 		}
862 	}
863 	else
864 	{
865 		f_cnt_t pos = _index;
866 		bool backwards = pos < _loopstart
867 			? false
868 			: *_backwards;
869 		f_cnt_t copied = 0;
870 
871 
872 		if( backwards )
873 		{
874 			copied = qMin( _frames, pos - _loopstart );
875 			for( int i=0; i < copied; i++ )
876 			{
877 				(*_tmp)[i][0] = m_data[ pos - i ][0];
878 				(*_tmp)[i][1] = m_data[ pos - i ][1];
879 			}
880 			pos -= copied;
881 			if( pos == _loopstart ) backwards = false;
882 		}
883 		else
884 		{
885 			copied = qMin( _frames, _loopend - pos );
886 			memcpy( *_tmp, m_data + pos, copied * BYTES_PER_FRAME );
887 			pos += copied;
888 			if( pos == _loopend ) backwards = true;
889 		}
890 
891 		while( copied < _frames )
892 		{
893 			if( backwards )
894 			{
895 				f_cnt_t todo = qMin( _frames - copied, pos - _loopstart );
896 				for ( int i=0; i < todo; i++ )
897 				{
898 					(*_tmp)[ copied + i ][0] = m_data[ pos - i ][0];
899 					(*_tmp)[ copied + i ][1] = m_data[ pos - i ][1];
900 				}
901 				pos -= todo;
902 				copied += todo;
903 				if( pos <= _loopstart ) backwards = false;
904 			}
905 			else
906 			{
907 				f_cnt_t todo = qMin( _frames - copied, _loopend - pos );
908 				memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME );
909 				pos += todo;
910 				copied += todo;
911 				if( pos >= _loopend ) backwards = true;
912 			}
913 		}
914 		*_backwards = backwards;
915 	}
916 
917 	return *_tmp;
918 }
919 
920 
921 
922 
getLoopedIndex(f_cnt_t _index,f_cnt_t _startf,f_cnt_t _endf) const923 f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const
924 {
925 	if( _index < _endf )
926 	{
927 		return _index;
928 	}
929 	return _startf + ( _index - _startf )
930 				% ( _endf - _startf );
931 }
932 
933 
getPingPongIndex(f_cnt_t _index,f_cnt_t _startf,f_cnt_t _endf) const934 f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const
935 {
936 	if( _index < _endf )
937 	{
938 		return _index;
939 	}
940 	const f_cnt_t looplen = _endf - _startf;
941 	const f_cnt_t looppos = ( _index - _endf ) % ( looplen*2 );
942 
943 	return ( looppos < looplen )
944 		? _endf - looppos
945 		: _startf + ( looppos - looplen );
946 }
947 
948 
visualize(QPainter & _p,const QRect & _dr,const QRect & _clip,f_cnt_t _from_frame,f_cnt_t _to_frame)949 void SampleBuffer::visualize( QPainter & _p, const QRect & _dr,
950 							const QRect & _clip, f_cnt_t _from_frame, f_cnt_t _to_frame )
951 {
952 	if( m_frames == 0 ) return;
953 
954 	const bool focus_on_range = _to_frame <= m_frames
955 					&& 0 <= _from_frame && _from_frame < _to_frame;
956 	//_p.setClipRect( _clip );
957 	const int w = _dr.width();
958 	const int h = _dr.height();
959 
960 	const int yb = h / 2 + _dr.y();
961 	const float y_space = h*0.5f;
962 	const int nb_frames = focus_on_range ? _to_frame - _from_frame : m_frames;
963 
964 	const int fpp = tLimit<int>( nb_frames / w, 1, 20 );
965 	QPointF * l = new QPointF[nb_frames / fpp + 1];
966 	QPointF * r = new QPointF[nb_frames / fpp + 1];
967 	int n = 0;
968 	const int xb = _dr.x();
969 	const int first = focus_on_range ? _from_frame : 0;
970 	const int last = focus_on_range ? _to_frame : m_frames;
971 	for( int frame = first; frame < last; frame += fpp )
972 	{
973 		l[n] = QPointF( xb + ( (frame - first) * double( w ) / nb_frames ),
974 			( yb - ( m_data[frame][0] * y_space * m_amplification ) ) );
975 		r[n] = QPointF( xb + ( (frame - first) * double( w ) / nb_frames ),
976 			( yb - ( m_data[frame][1] * y_space * m_amplification ) ) );
977 		++n;
978 	}
979 	_p.setRenderHint( QPainter::Antialiasing );
980 	_p.drawPolyline( l, nb_frames / fpp );
981 	_p.drawPolyline( r, nb_frames / fpp );
982 	delete[] l;
983 	delete[] r;
984 }
985 
986 
987 
988 
openAudioFile() const989 QString SampleBuffer::openAudioFile() const
990 {
991 	FileDialog ofd( NULL, tr( "Open audio file" ) );
992 
993 	QString dir;
994 	if( !m_audioFile.isEmpty() )
995 	{
996 		QString f = m_audioFile;
997 		if( QFileInfo( f ).isRelative() )
998 		{
999 			f = ConfigManager::inst()->userSamplesDir() + f;
1000 			if( QFileInfo( f ).exists() == false )
1001 			{
1002 				f = ConfigManager::inst()->factorySamplesDir() +
1003 								m_audioFile;
1004 			}
1005 		}
1006 		dir = QFileInfo( f ).absolutePath();
1007 	}
1008 	else
1009 	{
1010 		dir = ConfigManager::inst()->userSamplesDir();
1011 	}
1012 	// change dir to position of previously opened file
1013 	ofd.setDirectory( dir );
1014 	ofd.setFileMode( FileDialog::ExistingFiles );
1015 
1016 	// set filters
1017 	QStringList types;
1018 	types << tr( "All Audio-Files (*.wav *.ogg *.ds *.flac *.spx *.voc "
1019 					"*.aif *.aiff *.au *.raw)" )
1020 		<< tr( "Wave-Files (*.wav)" )
1021 		<< tr( "OGG-Files (*.ogg)" )
1022 		<< tr( "DrumSynth-Files (*.ds)" )
1023 		<< tr( "FLAC-Files (*.flac)" )
1024 		<< tr( "SPEEX-Files (*.spx)" )
1025 		//<< tr( "MP3-Files (*.mp3)" )
1026 		//<< tr( "MIDI-Files (*.mid)" )
1027 		<< tr( "VOC-Files (*.voc)" )
1028 		<< tr( "AIFF-Files (*.aif *.aiff)" )
1029 		<< tr( "AU-Files (*.au)" )
1030 		<< tr( "RAW-Files (*.raw)" )
1031 		//<< tr( "MOD-Files (*.mod)" )
1032 		;
1033 	ofd.setNameFilters( types );
1034 	if( !m_audioFile.isEmpty() )
1035 	{
1036 		// select previously opened file
1037 		ofd.selectFile( QFileInfo( m_audioFile ).fileName() );
1038 	}
1039 
1040 	if( ofd.exec () == QDialog::Accepted )
1041 	{
1042 		if( ofd.selectedFiles().isEmpty() )
1043 		{
1044 			return QString::null;
1045 		}
1046 		return tryToMakeRelative( ofd.selectedFiles()[0] );
1047 	}
1048 
1049 	return QString::null;
1050 }
1051 
1052 
1053 
1054 
openAndSetAudioFile()1055 QString SampleBuffer::openAndSetAudioFile()
1056 {
1057 	QString fileName = this->openAudioFile();
1058 
1059 	if(!fileName.isEmpty())
1060 	{
1061 		this->setAudioFile( fileName );
1062 	}
1063 
1064 	return fileName;
1065 }
1066 
1067 
openAndSetWaveformFile()1068 QString SampleBuffer::openAndSetWaveformFile()
1069 {
1070 	if( m_audioFile.isEmpty() )
1071 	{
1072 		m_audioFile = ConfigManager::inst()->factorySamplesDir() + "waveforms/10saw.flac";
1073 	}
1074 
1075 	QString fileName = this->openAudioFile();
1076 
1077 	if(!fileName.isEmpty())
1078 	{
1079 		this->setAudioFile( fileName );
1080 	}
1081 	else
1082 	{
1083 		m_audioFile = "";
1084 	}
1085 
1086 	return fileName;
1087 }
1088 
1089 
1090 
1091 #undef LMMS_HAVE_FLAC_STREAM_ENCODER_H	/* not yet... */
1092 #undef LMMS_HAVE_FLAC_STREAM_DECODER_H
1093 
1094 #ifdef LMMS_HAVE_FLAC_STREAM_ENCODER_H
flacStreamEncoderWriteCallback(const FLAC__StreamEncoder *,const FLAC__byte _buffer[],unsigned int,unsigned int _bytes,unsigned int,void * _client_data)1095 FLAC__StreamEncoderWriteStatus flacStreamEncoderWriteCallback(
1096 					const FLAC__StreamEncoder *
1097 								/*_encoder*/,
1098 					const FLAC__byte _buffer[],
1099 					unsigned int/* _samples*/,
1100 					unsigned int _bytes,
1101 					unsigned int/* _current_frame*/,
1102 					void * _client_data )
1103 {
1104 /*	if( _bytes == 0 )
1105 	{
1106 		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
1107 	}*/
1108 	return ( static_cast<QBuffer *>( _client_data )->write(
1109 				(const char *) _buffer, _bytes ) ==
1110 								(int) _bytes ) ?
1111 				FLAC__STREAM_ENCODER_WRITE_STATUS_OK :
1112 				FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
1113 }
1114 
1115 
flacStreamEncoderMetadataCallback(const FLAC__StreamEncoder *,const FLAC__StreamMetadata * _metadata,void * _client_data)1116 void flacStreamEncoderMetadataCallback( const FLAC__StreamEncoder *,
1117 					const FLAC__StreamMetadata * _metadata,
1118 					void * _client_data )
1119 {
1120 	QBuffer * b = static_cast<QBuffer *>( _client_data );
1121 	b->seek( 0 );
1122 	b->write( (const char *) _metadata, sizeof( *_metadata ) );
1123 }
1124 
1125 #endif
1126 
1127 
1128 
toBase64(QString & _dst) const1129 QString & SampleBuffer::toBase64( QString & _dst ) const
1130 {
1131 #ifdef LMMS_HAVE_FLAC_STREAM_ENCODER_H
1132 	const f_cnt_t FRAMES_PER_BUF = 1152;
1133 
1134 	FLAC__StreamEncoder * flac_enc = FLAC__stream_encoder_new();
1135 	FLAC__stream_encoder_set_channels( flac_enc, DEFAULT_CHANNELS );
1136 	FLAC__stream_encoder_set_blocksize( flac_enc, FRAMES_PER_BUF );
1137 /*	FLAC__stream_encoder_set_do_exhaustive_model_search( flac_enc, true );
1138 	FLAC__stream_encoder_set_do_mid_side_stereo( flac_enc, true );*/
1139 	FLAC__stream_encoder_set_sample_rate( flac_enc,
1140 					Engine::mixer()->sampleRate() );
1141 	QBuffer ba_writer;
1142 	ba_writer.open( QBuffer::WriteOnly );
1143 
1144 	FLAC__stream_encoder_set_write_callback( flac_enc,
1145 					flacStreamEncoderWriteCallback );
1146 	FLAC__stream_encoder_set_metadata_callback( flac_enc,
1147 					flacStreamEncoderMetadataCallback );
1148 	FLAC__stream_encoder_set_client_data( flac_enc, &ba_writer );
1149 	if( FLAC__stream_encoder_init( flac_enc ) != FLAC__STREAM_ENCODER_OK )
1150 	{
1151 		printf( "error within FLAC__stream_encoder_init()!\n" );
1152 	}
1153 	f_cnt_t frame_cnt = 0;
1154 	while( frame_cnt < m_frames )
1155 	{
1156 		f_cnt_t remaining = qMin<f_cnt_t>( FRAMES_PER_BUF,
1157 							m_frames - frame_cnt );
1158 		FLAC__int32 buf[FRAMES_PER_BUF * DEFAULT_CHANNELS];
1159 		for( f_cnt_t f = 0; f < remaining; ++f )
1160 		{
1161 			for( ch_cnt_t ch = 0; ch < DEFAULT_CHANNELS; ++ch )
1162 			{
1163 				buf[f*DEFAULT_CHANNELS+ch] = (FLAC__int32)(
1164 					Mixer::clip( m_data[f+frame_cnt][ch] ) *
1165 						OUTPUT_SAMPLE_MULTIPLIER );
1166 			}
1167 		}
1168 		FLAC__stream_encoder_process_interleaved( flac_enc, buf,
1169 								remaining );
1170 		frame_cnt += remaining;
1171 	}
1172 	FLAC__stream_encoder_finish( flac_enc );
1173 	FLAC__stream_encoder_delete( flac_enc );
1174 	printf("%d %d\n", frame_cnt, (int)ba_writer.size() );
1175 	ba_writer.close();
1176 
1177 	base64::encode( ba_writer.buffer().data(), ba_writer.buffer().size(),
1178 									_dst );
1179 
1180 
1181 #else	/* LMMS_HAVE_FLAC_STREAM_ENCODER_H */
1182 
1183 	base64::encode( (const char *) m_data,
1184 					m_frames * sizeof( sampleFrame ), _dst );
1185 
1186 #endif	/* LMMS_HAVE_FLAC_STREAM_ENCODER_H */
1187 
1188 	return _dst;
1189 }
1190 
1191 
1192 
1193 
resample(const sample_rate_t _src_sr,const sample_rate_t _dst_sr)1194 SampleBuffer * SampleBuffer::resample( const sample_rate_t _src_sr,
1195 						const sample_rate_t _dst_sr )
1196 {
1197 	sampleFrame * data = m_data;
1198 	const f_cnt_t frames = m_frames;
1199 	const f_cnt_t dst_frames = static_cast<f_cnt_t>( frames /
1200 					(float) _src_sr * (float) _dst_sr );
1201 	SampleBuffer * dst_sb = new SampleBuffer( dst_frames );
1202 	sampleFrame * dst_buf = dst_sb->m_origData;
1203 
1204 	// yeah, libsamplerate, let's rock with sinc-interpolation!
1205 	int error;
1206 	SRC_STATE * state;
1207 	if( ( state = src_new( SRC_SINC_MEDIUM_QUALITY,
1208 					DEFAULT_CHANNELS, &error ) ) != NULL )
1209 	{
1210 		SRC_DATA src_data;
1211 		src_data.end_of_input = 1;
1212 		src_data.data_in = data[0];
1213 		src_data.data_out = dst_buf[0];
1214 		src_data.input_frames = frames;
1215 		src_data.output_frames = dst_frames;
1216 		src_data.src_ratio = (double) _dst_sr / _src_sr;
1217 		if( ( error = src_process( state, &src_data ) ) )
1218 		{
1219 			printf( "SampleBuffer: error while resampling: %s\n",
1220 							src_strerror( error ) );
1221 		}
1222 		src_delete( state );
1223 	}
1224 	else
1225 	{
1226 		printf( "Error: src_new() failed in sample_buffer.cpp!\n" );
1227 	}
1228 	dst_sb->update();
1229 	return dst_sb;
1230 }
1231 
1232 
1233 
1234 
setAudioFile(const QString & _audio_file)1235 void SampleBuffer::setAudioFile( const QString & _audio_file )
1236 {
1237 	m_audioFile = tryToMakeRelative( _audio_file );
1238 	update();
1239 }
1240 
1241 
1242 
1243 #ifdef LMMS_HAVE_FLAC_STREAM_DECODER_H
1244 
1245 struct flacStreamDecoderClientData
1246 {
1247 	QBuffer * read_buffer;
1248 	QBuffer * write_buffer;
1249 } ;
1250 
1251 
1252 
flacStreamDecoderReadCallback(const FLAC__StreamDecoder *,FLAC__byte * _buffer,unsigned int * _bytes,void * _client_data)1253 FLAC__StreamDecoderReadStatus flacStreamDecoderReadCallback(
1254 					const FLAC__StreamDecoder *
1255 								/*_decoder*/,
1256 					FLAC__byte * _buffer,
1257 					unsigned int * _bytes,
1258 					void * _client_data )
1259 {
1260 	int res = static_cast<flacStreamDecoderClientData *>(
1261 					_client_data )->read_buffer->read(
1262 						(char *) _buffer, *_bytes );
1263 
1264 	if( res > 0 )
1265 	{
1266 		*_bytes = res;
1267 		return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
1268 
1269 	}
1270 	*_bytes = 0;
1271 	return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
1272 }
1273 
1274 
1275 
1276 
flacStreamDecoderWriteCallback(const FLAC__StreamDecoder *,const FLAC__Frame * _frame,const FLAC__int32 * const _buffer[],void * _client_data)1277 FLAC__StreamDecoderWriteStatus flacStreamDecoderWriteCallback(
1278 					const FLAC__StreamDecoder *
1279 								/*_decoder*/,
1280 					const FLAC__Frame * _frame,
1281 					const FLAC__int32 * const _buffer[],
1282 					void * _client_data )
1283 {
1284 	if( _frame->header.channels != 2 )
1285 	{
1286 		printf( "channels != 2 in "
1287 					"flacStreamDecoderWriteCallback()\n" );
1288 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
1289 	}
1290 
1291 	if( _frame->header.bits_per_sample != 16 )
1292 	{
1293 		printf( "bits_per_sample != 16 in "
1294 					"flacStreamDecoderWriteCallback()\n" );
1295 		return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
1296 	}
1297 
1298 	const f_cnt_t frames = _frame->header.blocksize;
1299 	for( f_cnt_t frame = 0; frame < frames; ++frame )
1300 	{
1301 		sampleFrame sframe = { _buffer[0][frame] /
1302 						OUTPUT_SAMPLE_MULTIPLIER,
1303 					_buffer[1][frame] /
1304 						OUTPUT_SAMPLE_MULTIPLIER
1305 					} ;
1306 		static_cast<flacStreamDecoderClientData *>(
1307 					_client_data )->write_buffer->write(
1308 				(const char *) sframe, sizeof( sframe ) );
1309 	}
1310 	return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
1311 }
1312 
1313 
flacStreamDecoderMetadataCallback(const FLAC__StreamDecoder *,const FLAC__StreamMetadata *,void *)1314 void flacStreamDecoderMetadataCallback( const FLAC__StreamDecoder *,
1315 					const FLAC__StreamMetadata *,
1316 					void * /*_client_data*/ )
1317 {
1318 	printf("stream decoder metadata callback\n");
1319 /*	QBuffer * b = static_cast<QBuffer *>( _client_data );
1320 	b->seek( 0 );
1321 	b->write( (const char *) _metadata, sizeof( *_metadata ) );*/
1322 }
1323 
1324 
flacStreamDecoderErrorCallback(const FLAC__StreamDecoder *,FLAC__StreamDecoderErrorStatus _status,void *)1325 void flacStreamDecoderErrorCallback( const FLAC__StreamDecoder *,
1326 					FLAC__StreamDecoderErrorStatus _status,
1327 					void * /*_client_data*/ )
1328 {
1329 	printf("error callback! %d\n", _status);
1330 	// what to do now??
1331 }
1332 
1333 #endif
1334 
1335 
loadFromBase64(const QString & _data)1336 void SampleBuffer::loadFromBase64( const QString & _data )
1337 {
1338 	char * dst = NULL;
1339 	int dsize = 0;
1340 	base64::decode( _data, &dst, &dsize );
1341 
1342 #ifdef LMMS_HAVE_FLAC_STREAM_DECODER_H
1343 
1344 	QByteArray orig_data = QByteArray::fromRawData( dst, dsize );
1345 	QBuffer ba_reader( &orig_data );
1346 	ba_reader.open( QBuffer::ReadOnly );
1347 
1348 	QBuffer ba_writer;
1349 	ba_writer.open( QBuffer::WriteOnly );
1350 
1351 	flacStreamDecoderClientData cdata = { &ba_reader, &ba_writer } ;
1352 
1353 	FLAC__StreamDecoder * flac_dec = FLAC__stream_decoder_new();
1354 
1355 	FLAC__stream_decoder_set_read_callback( flac_dec,
1356 					flacStreamDecoderReadCallback );
1357 	FLAC__stream_decoder_set_write_callback( flac_dec,
1358 					flacStreamDecoderWriteCallback );
1359 	FLAC__stream_decoder_set_error_callback( flac_dec,
1360 					flacStreamDecoderErrorCallback );
1361 	FLAC__stream_decoder_set_metadata_callback( flac_dec,
1362 					flacStreamDecoderMetadataCallback );
1363 	FLAC__stream_decoder_set_client_data( flac_dec, &cdata );
1364 
1365 	FLAC__stream_decoder_init( flac_dec );
1366 
1367 	FLAC__stream_decoder_process_until_end_of_stream( flac_dec );
1368 
1369 	FLAC__stream_decoder_finish( flac_dec );
1370 	FLAC__stream_decoder_delete( flac_dec );
1371 
1372 	ba_reader.close();
1373 
1374 	orig_data = ba_writer.buffer();
1375 	printf("%d\n", (int) orig_data.size() );
1376 
1377 	m_origFrames = orig_data.size() / sizeof( sampleFrame );
1378 	MM_FREE( m_origData );
1379 	m_origData = MM_ALLOC( sampleFrame, m_origFrames );
1380 	memcpy( m_origData, orig_data.data(), orig_data.size() );
1381 
1382 #else /* LMMS_HAVE_FLAC_STREAM_DECODER_H */
1383 
1384 	m_origFrames = dsize / sizeof( sampleFrame );
1385 	MM_FREE( m_origData );
1386 	m_origData = MM_ALLOC( sampleFrame, m_origFrames );
1387 	memcpy( m_origData, dst, dsize );
1388 
1389 #endif
1390 
1391 	delete[] dst;
1392 
1393 	m_audioFile = QString();
1394 	update();
1395 }
1396 
1397 
1398 
1399 
setStartFrame(const f_cnt_t _s)1400 void SampleBuffer::setStartFrame( const f_cnt_t _s )
1401 {
1402 	m_startFrame = _s;
1403 }
1404 
1405 
1406 
1407 
setEndFrame(const f_cnt_t _e)1408 void SampleBuffer::setEndFrame( const f_cnt_t _e )
1409 {
1410 	m_endFrame = _e;
1411 }
1412 
1413 
1414 
1415 
setAmplification(float _a)1416 void SampleBuffer::setAmplification( float _a )
1417 {
1418 	m_amplification = _a;
1419 	emit sampleUpdated();
1420 }
1421 
1422 
1423 
1424 
setReversed(bool _on)1425 void SampleBuffer::setReversed( bool _on )
1426 {
1427 	m_reversed = _on;
1428 	update( true );
1429 }
1430 
1431 
1432 
1433 
tryToMakeRelative(const QString & file)1434 QString SampleBuffer::tryToMakeRelative( const QString & file )
1435 {
1436 	if( QFileInfo( file ).isRelative() == false )
1437 	{
1438 		// Normalize the path
1439 		QString f( QDir::cleanPath( file ) );
1440 
1441 		// First, look in factory samples
1442 		// Isolate "samples/" from "data:/samples/"
1443 		QString samplesSuffix = ConfigManager::inst()->factorySamplesDir().mid( ConfigManager::inst()->dataDir().length() );
1444 
1445 		// Iterate over all valid "data:/" searchPaths
1446 		for ( const QString & path : QDir::searchPaths( "data" ) )
1447 		{
1448 			QString samplesPath = QDir::cleanPath( path + samplesSuffix ) + "/";
1449 			if ( f.startsWith( samplesPath ) )
1450 			{
1451 				return QString( f ).mid( samplesPath.length() );
1452 			}
1453 		}
1454 
1455 		// Next, look in user samples
1456 		QString usd = ConfigManager::inst()->userSamplesDir();
1457 		usd.replace( QDir::separator(), '/' );
1458 		if( f.startsWith( usd ) )
1459 		{
1460 			return QString( f ).mid( usd.length() );
1461 		}
1462 	}
1463 	return file;
1464 }
1465 
1466 
1467 
1468 
tryToMakeAbsolute(const QString & file)1469 QString SampleBuffer::tryToMakeAbsolute(const QString& file)
1470 {
1471 	QFileInfo f(file);
1472 
1473 	if(f.isRelative())
1474 	{
1475 		f = QFileInfo(ConfigManager::inst()->userSamplesDir() + file);
1476 
1477 		if(! f.exists())
1478 		{
1479 			f = QFileInfo(ConfigManager::inst()->factorySamplesDir() + file);
1480 		}
1481 	}
1482 
1483 	if (f.exists()) {
1484 		return f.absoluteFilePath();
1485 	}
1486 	return file;
1487 }
1488 
1489 
1490 
1491 
1492 
1493 
1494 
1495 
handleState(bool _varying_pitch,int interpolation_mode)1496 SampleBuffer::handleState::handleState( bool _varying_pitch, int interpolation_mode ) :
1497 	m_frameIndex( 0 ),
1498 	m_varyingPitch( _varying_pitch ),
1499 	m_isBackwards( false )
1500 {
1501 	int error;
1502 	m_interpolationMode = interpolation_mode;
1503 
1504 	if( ( m_resamplingData = src_new( interpolation_mode, DEFAULT_CHANNELS, &error ) ) == NULL )
1505 	{
1506 		qDebug( "Error: src_new() failed in sample_buffer.cpp!\n" );
1507 	}
1508 }
1509 
1510 
1511 
1512 
~handleState()1513 SampleBuffer::handleState::~handleState()
1514 {
1515 	src_delete( m_resamplingData );
1516 }
1517