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