root/trunk/libs/hydrogen/src/IO/disk_writer_driver.cpp @ 1467

Revision 1467, 8.3 KB (checked in by wolke, 3 years ago)

fix the export end of song problem

Line 
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20 *
21 */
22#include "DiskWriterDriver.h"
23
24#include <hydrogen/Preferences.h>
25#include <hydrogen/event_queue.h>
26#include <hydrogen/hydrogen.h>
27#include <hydrogen/Pattern.h>
28
29#include <pthread.h>
30#include <cassert>
31
32namespace H2Core
33{
34
35pthread_t diskWriterDriverThread;
36
37void* diskWriterDriver_thread( void* param )
38{
39        DiskWriterDriver *pDriver = ( DiskWriterDriver* )param;
40        _INFOLOG( "DiskWriterDriver thread start" );
41
42        // always rolling, no user interaction
43        pDriver->m_transport.m_status = TransportInfo::ROLLING;
44
45        SF_INFO soundInfo;
46        soundInfo.samplerate = pDriver->m_nSampleRate;
47//      soundInfo.frames = -1;//getNFrames();           ///\todo: da terminare
48        soundInfo.channels = 2;
49        //default format
50        int sfformat = 0x010000;
51        int bits = 0x0002;
52        //sf_format switch
53        if( pDriver->m_sFilename.endsWith(".aiff") || pDriver->m_sFilename.endsWith(".AIFF") )
54                sfformat =  0x020000;
55        if( pDriver->m_sFilename.endsWith(".flac") || pDriver->m_sFilename.endsWith(".FLAC") )
56                sfformat =  0x170000;
57
58        if( pDriver->m_nSampleDepth == 8 )
59                bits = 0x0001;
60        if( pDriver->m_nSampleDepth == 16 )
61                bits = 0x0002;
62        if( pDriver->m_nSampleDepth == 24 )
63                bits = 0x0003;
64        if( pDriver->m_nSampleDepth == 32 )
65                bits = 0x0004;
66
67        soundInfo.format =  sfformat|bits;
68
69        //ogg vorbis option
70        if( pDriver->m_sFilename.endsWith( ".ogg" ) | pDriver->m_sFilename.endsWith( ".OGG" ) )
71                soundInfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
72///format
73//          SF_FORMAT_WAV          = 0x010000,     /* Microsoft WAV format (little endian). */
74//          SF_FORMAT_AIFF         = 0x020000,     /* Apple/SGI AIFF format (big endian). */
75//          SF_FORMAT_AU           = 0x030000,     /* Sun/NeXT AU format (big endian). */
76//          SF_FORMAT_RAW          = 0x040000,     /* RAW PCM data. */
77//          SF_FORMAT_PAF          = 0x050000,     /* Ensoniq PARIS file format. */
78//          SF_FORMAT_SVX          = 0x060000,     /* Amiga IFF / SVX8 / SV16 format. */
79//          SF_FORMAT_NIST         = 0x070000,     /* Sphere NIST format. */
80//          SF_FORMAT_VOC          = 0x080000,     /* VOC files. */
81//          SF_FORMAT_IRCAM        = 0x0A0000,     /* Berkeley/IRCAM/CARL */
82//          SF_FORMAT_W64          = 0x0B0000,     /* Sonic Foundry's 64 bit RIFF/WAV */
83//          SF_FORMAT_MAT4         = 0x0C0000,     /* Matlab (tm) V4.2 / GNU Octave 2.0 */
84//          SF_FORMAT_MAT5         = 0x0D0000,     /* Matlab (tm) V5.0 / GNU Octave 2.1 */
85//          SF_FORMAT_PVF          = 0x0E0000,     /* Portable Voice Format */
86//          SF_FORMAT_XI           = 0x0F0000,     /* Fasttracker 2 Extended Instrument */
87//          SF_FORMAT_HTK          = 0x100000,     /* HMM Tool Kit format */
88//          SF_FORMAT_SDS          = 0x110000,     /* Midi Sample Dump Standard */
89//          SF_FORMAT_AVR          = 0x120000,     /* Audio Visual Research */
90//          SF_FORMAT_WAVEX        = 0x130000,     /* MS WAVE with WAVEFORMATEX */
91//          SF_FORMAT_SD2          = 0x160000,     /* Sound Designer 2 */
92//          SF_FORMAT_FLAC         = 0x170000,     /* FLAC lossless file format */
93//          SF_FORMAT_CAF          = 0x180000,     /* Core Audio File format */
94//          SF_FORMAT_OGG
95///bits
96//          SF_FORMAT_PCM_S8       = 0x0001,       /* Signed 8 bit data */
97//          SF_FORMAT_PCM_16       = 0x0002,       /* Signed 16 bit data */
98//          SF_FORMAT_PCM_24       = 0x0003,       /* Signed 24 bit data */
99//          SF_FORMAT_PCM_32       = 0x0004,       /* Signed 32 bit data */
100///used for ogg
101//          SF_FORMAT_VORBIS
102
103        if ( !sf_format_check( &soundInfo ) ) {
104                _ERRORLOG( "Error in soundInfo" );
105                return 0;
106        }
107
108
109        SNDFILE* m_file = sf_open( pDriver->m_sFilename.toLocal8Bit(), SFM_WRITE, &soundInfo );
110
111        float *pData = new float[ pDriver->m_nBufferSize * 2 ]; // always stereo
112
113        float *pData_L = pDriver->m_pOut_L;
114        float *pData_R = pDriver->m_pOut_R;
115
116
117        //calculate exaxt song frames.
118        std::vector<PatternList*> *pPatternColumns = Hydrogen::get_instance()->getSong()->get_pattern_group_vector();
119        int nColumns = pPatternColumns->size();
120
121        int nPatternSize;
122        int nSongSize = 0;
123        for ( int i = 0; i < nColumns; ++i ) {
124                PatternList *pColumn = ( *pPatternColumns )[ i ];
125                if ( pColumn->get_size() != 0 ) {
126                        nPatternSize = pColumn->get( 0 )->get_length();
127                } else {
128                        nPatternSize = MAX_NOTES;
129                }
130                nSongSize += nPatternSize;
131        }
132
133        float ticksize = pDriver->m_nSampleRate * 60.0 /  Hydrogen::get_instance()->getSong()->__bpm / 192 *4;
134        unsigned songLengthinFrames = ticksize * nSongSize;
135
136        unsigned frameNuber = 0;
137        int lastrun = 0;
138        while ( frameNuber < songLengthinFrames ) {
139
140                int usedbuffer = pDriver->m_nBufferSize;
141
142                if( songLengthinFrames - frameNuber <  pDriver->m_nBufferSize){
143                        lastrun = songLengthinFrames - frameNuber;
144                        usedbuffer = lastrun;
145                        _ERRORLOG(QString("framenuber %1 lastrun: %2").arg(frameNuber).arg(lastrun));
146                };
147                frameNuber += usedbuffer;
148                int ret = pDriver->m_processCallback( usedbuffer, NULL );
149
150                for ( unsigned i = 0; i < usedbuffer; i++ ) {
151                        if(pData_L[i] > 1){
152                                pData[i * 2] = 1;
153                        }
154                        else if(pData_L[i] < -1){
155                                pData[i * 2] = -1;
156                        }else
157                        {
158                                pData[i * 2] = pData_L[i];
159                        }
160
161                        if(pData_R[i] > 1){
162                                pData[i * 2 + 1] = 1;
163                        }
164                        else if(pData_R[i] < -1){
165                                pData[i * 2 + 1] = -1;
166                        }else
167                        {
168                                pData[i * 2 + 1] = pData_R[i];
169                        }
170                }
171                int res = sf_writef_float( m_file, pData, usedbuffer );
172                if ( res != ( int )usedbuffer ) {
173                        _ERRORLOG( "Error during sf_write_float" );
174                }
175
176                float fPercent = ( float ) frameNuber / ( float )songLengthinFrames * 100.0;
177                EventQueue::get_instance()->push_event( EVENT_PROGRESS, ( int )fPercent );
178//              frameNuber += lastrun;
179        }
180
181//      EventQueue::get_instance()->push_event( EVENT_PROGRESS, 100 );
182        delete[] pData;
183        pData = NULL;
184
185        sf_close( m_file );
186
187        _INFOLOG( "DiskWriterDriver thread end" );
188
189        pthread_exit( NULL );
190
191        Hydrogen::get_instance()->stopExportSong();
192        return NULL;
193}
194
195
196
197
198DiskWriterDriver::DiskWriterDriver( audioProcessCallback processCallback, unsigned nSamplerate, const QString& sFilename, int nSampleDepth )
199                : AudioOutput( "DiskWriterDriver" )
200                , m_nSampleRate( nSamplerate )
201                , m_sFilename( sFilename )
202                , m_nSampleDepth ( nSampleDepth )
203                , m_processCallback( processCallback )
204{
205        INFOLOG( "INIT" );
206}
207
208
209
210DiskWriterDriver::~DiskWriterDriver()
211{
212        INFOLOG( "DESTROY" );
213}
214
215
216
217int DiskWriterDriver::init( unsigned nBufferSize )
218{
219        INFOLOG( QString( "Init, %1 samples" ).arg( nBufferSize ) );
220
221        m_nBufferSize = nBufferSize;
222        m_pOut_L = new float[nBufferSize];
223        m_pOut_R = new float[nBufferSize];
224
225        return 0;
226}
227
228
229
230///
231/// Connect
232/// return 0: Ok
233///
234int DiskWriterDriver::connect()
235{
236        INFOLOG( "[connect]" );
237
238        pthread_attr_t attr;
239        pthread_attr_init( &attr );
240
241        pthread_create( &diskWriterDriverThread, &attr, diskWriterDriver_thread, this );
242
243        return 0;
244}
245
246
247
248/// disconnect
249void DiskWriterDriver::disconnect()
250{
251        INFOLOG( "[disconnect]" );
252
253        delete[] m_pOut_L;
254        m_pOut_L = NULL;
255
256        delete[] m_pOut_R;
257        m_pOut_R = NULL;
258}
259
260
261
262unsigned DiskWriterDriver::getSampleRate()
263{
264        return m_nSampleRate;
265}
266
267
268
269void DiskWriterDriver::play()
270{
271        m_transport.m_status = TransportInfo::ROLLING;
272}
273
274
275
276void DiskWriterDriver::stop()
277{
278        m_transport.m_status = TransportInfo::STOPPED;
279}
280
281
282
283void DiskWriterDriver::locate( unsigned long nFrame )
284{
285        INFOLOG( QString( "Locate: %1" ).arg( nFrame ) );
286        m_transport.m_nFrames = nFrame;
287}
288
289
290
291void DiskWriterDriver::updateTransportInfo()
292{
293//      errorLog( "[updateTransportInfo] not implemented yet" );
294        // not used
295}
296
297
298
299void DiskWriterDriver::setBpm( float fBPM )
300{
301        INFOLOG( QString( "SetBpm: %1" ).arg( fBPM ) );
302        m_transport.m_nBPM = fBPM;
303}
304
305
306};
Note: See TracBrowser for help on using the browser.