root/branches/undo/src/core/src/basics/drumkit.cpp @ 2229

Revision 2229, 12.6 KB (checked in by wolke, 2 years ago)

fix save sound library par save soundlibrary dialogue.
fix save sound library par soundlibrary properties dialogue.

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
23#include <hydrogen/basics/drumkit.h>
24#include <hydrogen/hydrogen.h>
25#include <hydrogen/config.h>
26#ifdef H2CORE_HAVE_LIBARCHIVE
27#include <archive.h>
28#include <archive_entry.h>
29#else
30#ifndef WIN32
31#include <fcntl.h>
32#include <errno.h>
33#include <zlib.h>
34#include <libtar.h>
35#endif
36#endif
37
38#include <hydrogen/basics/sample.h>
39#include <hydrogen/basics/instrument.h>
40#include <hydrogen/basics/instrument_list.h>
41#include <hydrogen/basics/instrument_layer.h>
42
43#include <hydrogen/helpers/xml.h>
44#include <hydrogen/helpers/filesystem.h>
45#include <hydrogen/helpers/legacy.h>
46
47namespace H2Core {
48
49const char* Drumkit::__class_name = "Drumkit";
50
51Drumkit::Drumkit() : Object( __class_name ), __samples_loaded( false ), __instruments( 0 ) { }
52
53Drumkit::Drumkit( Drumkit* other ) :
54    Object( __class_name ),
55    __path( other->get_path() ),
56    __name( other->get_name() ),
57    __author( other->get_author() ),
58    __info( other->get_info() ),
59    __license( other->get_license() ),
60    __samples_loaded( other->samples_loaded() ) {
61    __instruments = new InstrumentList( other->get_instruments() );
62}
63
64Drumkit::~Drumkit() {
65    if( __instruments ) delete __instruments;
66}
67
68Drumkit* Drumkit::load( const QString& dk_dir, bool load_samples ) {
69    INFOLOG( QString( "Load drumkit %1" ).arg( dk_dir ) );
70    if( !Filesystem::drumkit_valid( dk_dir ) ) {
71        ERRORLOG( QString( "%1 is not valid drumkit" ).arg( dk_dir ) );
72        return 0;
73    }
74    return load_file( Filesystem::drumkit_file( dk_dir ), load_samples );
75}
76
77Drumkit* Drumkit::load_file( const QString& dk_path, bool load_samples ) {
78    XMLDoc doc;
79    if( !doc.read( dk_path, Filesystem::drumkit_xsd() ) ) {
80        return Legacy::load_drumkit( dk_path );
81    }
82    XMLNode root = doc.firstChildElement( "drumkit_info" );
83    if ( root.isNull() ) {
84        ERRORLOG( "drumkit_info node not found" );
85        return 0;
86    }
87    Drumkit* drumkit = Drumkit::load_from( &root, dk_path.left( dk_path.lastIndexOf( "/" ) ) );
88    if( load_samples ) drumkit->load_samples();
89    /*
90    if( load_samples ) {
91        InstrumentList* instruments = drumkit->get_instruments();
92        for( int i=0; i<instruments->size(); i++ ) {
93            Instrument* instrument = ( *instruments )[i];
94            for ( int n = 0; n < MAX_LAYERS; n++ ) {
95                InstrumentLayer* layer = instrument->get_layer( n );
96                if( layer ) {
97                    Sample* sample = layer->get_sample();
98                    if( sample ) sample->load();
99                }
100            }
101        }
102    }
103    */
104    return drumkit;
105}
106
107Drumkit* Drumkit::load_from( XMLNode* node, const QString& dk_path ) {
108    QString drumkit_name = node->read_string( "name", "", false, false );
109    if ( drumkit_name.isEmpty() ) {
110        ERRORLOG( "Drumkit has no name, abort" );
111        return 0;
112    }
113    Drumkit* drumkit = new Drumkit();
114    drumkit->__path = dk_path;
115    drumkit->__name = drumkit_name;
116    drumkit->__author = node->read_string( "author", "undefined author" );
117    drumkit->__info = node->read_string( "info", "defaultInfo" );
118    drumkit->__license = node->read_string( "license", "undefined license" );
119    XMLNode instruments_node = node->firstChildElement( "instrumentList" );
120    if ( instruments_node.isNull() ) {
121        WARNINGLOG( "instrumentList node not found" );
122        drumkit->set_instruments( new InstrumentList() );
123    } else {
124        drumkit->set_instruments( InstrumentList::load_from( &instruments_node, dk_path ) );
125    }
126    //if( drumkit->__logger->should_log( Logger::Debug ) ) drumkit->dump();
127    return drumkit;
128}
129
130void Drumkit::load_samples( ) {
131    INFOLOG( QString( "Loading drumkit %1 instrument samples" ).arg( __name ) );
132    if( !__samples_loaded ) {
133        __instruments->load_samples();
134        __samples_loaded = true;
135    }
136}
137
138void Drumkit::unload_samples( ) {
139    INFOLOG( QString( "Unloading drumkit %1 instrument samples" ).arg( __name ) );
140    if( __samples_loaded ) {
141        __instruments->unload_samples();
142        __samples_loaded = false;
143    }
144}
145
146bool Drumkit::save( const QString& name, const QString& author, const QString& info, const QString& license, InstrumentList* instruments, bool overwrite ) {
147
148    Drumkit* drumkit = new Drumkit();
149    drumkit->set_name( name );
150    drumkit->set_author( author );
151    drumkit->set_info( info );
152    drumkit->set_license( license );
153    drumkit->set_instruments( instruments );
154    bool ret = drumkit->save( overwrite );
155    drumkit->~Object();
156    return ret;
157}
158
159bool Drumkit::save( bool overwrite ) {
160    INFOLOG( QString( "New drumkit dir " + Filesystem::usr_drumkits_dir() + "/" + __name ) );
161    return  save( QString( Filesystem::usr_drumkits_dir() + "/" + __name ), overwrite );
162}
163
164bool Drumkit::save( const QString& dk_dir, bool overwrite ) {
165    if( !Filesystem::mkdir( dk_dir ) ) {
166        return false;
167    }
168    bool ret = save_file( Filesystem::drumkit_file( dk_dir ), overwrite );
169    if ( ret ) {
170        ret = save_samples( dk_dir, overwrite );
171    }
172    return ret;
173}
174
175bool Drumkit::save_file( const QString& dk_path, bool overwrite ) {
176    INFOLOG( QString( "Saving drumkit definition into %1" ).arg( dk_path ) );
177    if( Filesystem::file_exists( dk_path, true ) && !overwrite ) {
178        ERRORLOG( QString( "drumkit %1 already exists" ).arg( dk_path ) );
179        return false;
180    }
181    XMLDoc doc;
182    QDomProcessingInstruction header = doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" );
183    doc.appendChild( header );
184    XMLNode root = doc.createElement( "drumkit_info" );
185    QDomElement el = root.toElement();
186    el.setAttribute( "xmlns",XMLNS_BASE"/drumkit" );
187    el.setAttribute( "xmlns:xsi",XMLNS_XSI );
188    save_to( &root );
189    doc.appendChild( root );
190    return doc.write( dk_path );
191}
192
193void Drumkit::save_to( XMLNode* node ) {
194    node->write_string( "name", __name );
195    node->write_string( "author", __author );
196    node->write_string( "info", __info );
197    node->write_string( "license", __license );
198    __instruments->save_to( node );
199}
200
201bool Drumkit::save_samples( const QString& dk_dir, bool overwrite ) {
202    qDebug()<< QString( "Saving drumkit %1 samples into %2" ).arg( __name ).arg( dk_dir ) ;
203    if( !Filesystem::mkdir( dk_dir ) ) {
204        qDebug()<<( QString( "unable to create %1" ).arg( dk_dir ) );
205        return false;
206    }
207
208    InstrumentList* instruments = get_instruments();
209    for( int i=0; i<instruments->size(); i++ ) {
210        Instrument* instrument = ( *instruments )[i];
211        for ( int n = 0; n < MAX_LAYERS; n++ ) {
212            InstrumentLayer* layer = instrument->get_layer( n );
213            if( layer ) {
214                QString src =  layer->get_sample()->get_filepath();
215                QString dst = dk_dir + "/" + layer->get_sample()->get_filename();
216                if( !Filesystem::file_copy( src, dst ) ) {
217                    return false;
218                }
219            }
220        }
221    }
222    return true;
223}
224
225void Drumkit::set_instruments( InstrumentList* instruments ) {
226    if( __instruments!=0 ) delete __instruments;
227    __instruments = instruments;
228}
229
230bool Drumkit::remove( const QString& dk_name ) {
231    QString dk_dir = Filesystem::drumkit_path( dk_name );
232    if( !Filesystem::drumkit_valid( dk_dir ) ) {
233        ERRORLOG( QString( "%1 is not valid drumkit" ).arg( dk_dir ) );
234        return false;
235    }
236    _INFOLOG( QString( "Removing drumkit: %1" ).arg( dk_dir ) );
237    if( !Filesystem::rm( dk_dir, true ) ) {
238        _ERRORLOG( QString( "Unable to remove drumkit: %1" ).arg( dk_dir ) );
239        return false;
240    }
241    return true;
242}
243
244void Drumkit::dump() {
245    DEBUGLOG( "Drumkit dump" );
246    DEBUGLOG( " |- Path = " + __path );
247    DEBUGLOG( " |- Name = " + __name );
248    DEBUGLOG( " |- Author = " + __author );
249    DEBUGLOG( " |- Info = " + __info );
250    DEBUGLOG( " |- Instrument list" );
251    for ( int i=0; i<__instruments->size(); i++ ) {
252        Instrument* instrument = ( *__instruments )[i];
253        DEBUGLOG( QString( "  |- (%1 of %2) Name = %3" )
254                  .arg( i )
255                  .arg( __instruments->size()-1 )
256                  .arg( instrument->get_name() )
257                );
258        for ( int j=0; j<MAX_LAYERS; j++ ) {
259            InstrumentLayer* layer = instrument->get_layer( j );
260            if ( layer ) {
261                Sample* sample = layer->get_sample();
262                if ( sample ) {
263                    DEBUGLOG( QString( "   |- %1 [%2]" ).arg( sample->get_filepath() ).arg( sample->is_empty() ) );
264                } else {
265                    DEBUGLOG( "   |- NULL sample" );
266                }
267            }
268        }
269    }
270}
271
272bool Drumkit::install( const QString& path ) {
273    _INFOLOG( QString( "Install drumkit %1" ).arg( path ) );
274#ifdef H2CORE_HAVE_LIBARCHIVE
275    int r;
276    struct archive* arch;
277    struct archive_entry* entry;
278    char newpath[1024];
279    arch = archive_read_new();
280    archive_read_support_compression_all( arch );
281    archive_read_support_format_all( arch );
282    if ( ( r = archive_read_open_file( arch, path.toLocal8Bit(), 10240 ) ) ) {
283        _ERRORLOG( QString( "archive_read_open_file() [%1] %2" ).arg( archive_errno( arch ) ).arg( archive_error_string( arch ) ) );
284        archive_read_close( arch );
285        archive_read_finish( arch );
286        return false;
287    }
288    bool ret = true;
289    QString dk_dir = Filesystem::usr_drumkits_dir() + "/";
290    while ( ( r = archive_read_next_header( arch, &entry ) ) != ARCHIVE_EOF ) {
291        if ( r != ARCHIVE_OK ) {
292            _ERRORLOG( QString( "archive_read_next_header() [%1] %2" ).arg( archive_errno( arch ) ).arg( archive_error_string( arch ) ) );
293            ret = false;
294            break;
295        }
296        QString np = dk_dir + archive_entry_pathname( entry );
297        strncpy( newpath, np.toLocal8Bit(), 1024 );
298        archive_entry_set_pathname( entry, newpath );
299        r = archive_read_extract( arch, entry, 0 );
300        if ( r == ARCHIVE_WARN ) {
301            _WARNINGLOG( QString( "archive_read_extract() [%1] %2" ).arg( archive_errno( arch ) ).arg( archive_error_string( arch ) ) );
302        } else if ( r != ARCHIVE_OK ) {
303            _ERRORLOG( QString( "archive_read_extract() [%1] %2" ).arg( archive_errno( arch ) ).arg( archive_error_string( arch ) ) );
304            ret = false;
305            break;
306        }
307    }
308    archive_read_close( arch );
309    archive_read_finish( arch );
310    return ret;
311#else // H2CORE_HAVE_LIBARCHIVE
312#ifndef WIN32
313    // GUNZIP
314    QString gzd_name = path.left( path.indexOf( "." ) ) + ".tar";
315    FILE* gzd_file = fopen( gzd_name.toLocal8Bit(), "wb" );
316    gzFile gzip_file = gzopen( path.toLocal8Bit(), "rb" );
317    if ( !gzip_file ) {
318        _ERRORLOG( QString( "Error reading drumkit file: %1" ).arg( path ) );
319        gzclose( gzip_file );
320        fclose( gzd_file );
321        return false;
322    }
323    uchar buf[4096];
324    while ( gzread( gzip_file, buf, 4096 ) > 0 ) {
325        fwrite( buf, sizeof( uchar ), 4096, gzd_file );
326    }
327    gzclose( gzip_file );
328    fclose( gzd_file );
329    // UNTAR
330    TAR* tar_file;
331    char tar_path[1024];
332    strncpy( tar_path, gzd_name.toLocal8Bit(), 1024 );
333    if ( tar_open( &tar_file, tar_path, NULL, O_RDONLY, 0, TAR_VERBOSE | TAR_GNU ) == -1 ) {
334        _ERRORLOG( QString( "tar_open(): %1" ).arg( QString::fromLocal8Bit( strerror( errno ) ) ) );
335        return false;
336    }
337    bool ret = true;
338    char dst_dir[1024];
339    QString dk_dir = Filesystem::usr_drumkits_dir() + "/";
340    strncpy( dst_dir, dk_dir.toLocal8Bit(), 1024 );
341    if ( tar_extract_all( tar_file, dst_dir ) != 0 ) {
342        _ERRORLOG( QString( "tar_extract_all(): %1" ).arg( QString::fromLocal8Bit( strerror( errno ) ) ) );
343        ret = false;
344    }
345    if ( tar_close( tar_file ) != 0 ) {
346        _ERRORLOG( QString( "tar_close(): %1" ).arg( QString::fromLocal8Bit( strerror( errno ) ) ) );
347        ret = false;
348    }
349    return ret;
350#else // WIN32
351    _ERRORLOG( "WIN32 NOT IMPLEMENTED" );
352    return false;
353#endif
354#endif
355}
356
357};
358
359/* vim: set softtabstop=4 expandtab: */
Note: See TracBrowser for help on using the browser.