1 /*************************************************************************** 2 SignalManager.h - manager class for multi channel signals 3 ------------------- 4 begin : Sun Oct 15 2000 5 copyright : (C) 2000 by Thomas Eschenbacher 6 email : Thomas.Eschenbacher@gmx.de 7 ***************************************************************************/ 8 9 /*************************************************************************** 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 ***************************************************************************/ 17 18 #ifndef SIGNAL_MANAGER_H 19 #define SIGNAL_MANAGER_H 20 21 #include "config.h" 22 23 #include <QtGlobal> 24 #include <QList> 25 #include <QMap> 26 #include <QObject> 27 #include <QRecursiveMutex> 28 #include <QString> 29 30 #include "libkwave/FileInfo.h" 31 #include "libkwave/Label.h" 32 #include "libkwave/MetaData.h" 33 #include "libkwave/MetaDataList.h" 34 #include "libkwave/PlaybackController.h" 35 #include "libkwave/ReaderMode.h" 36 #include "libkwave/Selection.h" 37 #include "libkwave/Signal.h" 38 #include "libkwave/undo/UndoManager.h" 39 40 class QBitmap; 41 class QFile; 42 class QUrl; 43 44 #define NEW_FILENAME i18n("New File") 45 46 namespace Kwave 47 { 48 49 class UndoAction; 50 class UndoInsertAction; 51 class UndoTransaction; 52 class UndoTransactionGuard; 53 class MultiTrackWriter; 54 class SampleReader; 55 class SignalWidget; 56 class Track; 57 class Writer; 58 59 /** 60 * The SignalManager class manages multi channel signals. 61 */ 62 class Q_DECL_EXPORT SignalManager: public QObject 63 { 64 Q_OBJECT 65 66 public: 67 /** Default constructor. */ 68 explicit SignalManager(QWidget *parent); 69 70 /** Default destructor */ 71 virtual ~SignalManager(); 72 73 /** 74 * Closes the current signal and loads a new file. 75 * @param url URL of the file to be loaded 76 * @return 0 if succeeded or error code < 0 77 */ 78 int loadFile(const QUrl &url); 79 80 /** 81 * Closes the current signal and creates a new empty signal. 82 * @param samples number of samples per track 83 * @param rate sample rate 84 * @param bits number of bits per sample 85 * @param tracks number of tracks 86 */ 87 void newSignal(sample_index_t samples, double rate, 88 unsigned int bits, unsigned int tracks); 89 90 /** 91 * Closes the current signal. 92 */ 93 void close(); 94 95 /** Returns true if the signal is closed */ isClosed()96 inline bool isClosed() { return m_closed; } 97 98 /** Returns true if the signal is empty. */ isEmpty()99 inline bool isEmpty() { return m_empty; } 100 101 /** Returns true if the signal is modified */ isModified()102 inline bool isModified() { return m_modified; } 103 104 /** Returns a reference to the playback controller. */ 105 Kwave::PlaybackController &playbackController(); 106 107 /** 108 * Execute a Kwave text command 109 * @param command a text command 110 * @return zero if succeeded or negative error code if failed 111 * @retval -ENOSYS is returned if the command is unknown in this component 112 */ 113 int executeCommand(const QString &command); 114 115 /** 116 * Returns a reference to the current name of the signal. If no signal is 117 * loaded the string is zero-length. 118 */ 119 QString signalName(); 120 121 /** 122 * Returns the current sample resolution in bits per sample 123 */ bits()124 inline unsigned int bits() const { 125 return Kwave::FileInfo(m_meta_data).bits(); 126 } 127 128 /** Returns the current sample rate in samples per second */ rate()129 inline double rate() const { 130 return Kwave::FileInfo(m_meta_data).rate(); 131 } 132 133 /** Returns the current number of tracks */ tracks()134 inline unsigned int tracks() { return m_signal.tracks(); } 135 136 /** 137 * Returns the number of samples in the current signal. Will be 138 * zero if no signal is loaded. 139 */ length()140 inline sample_index_t length() { return m_signal.length(); } 141 142 /** Returns a reference to the current selection */ selection()143 inline Kwave::Selection &selection() { return m_selection; } 144 145 /** 146 * Returns true if a given track is selected. If the track does 147 * not exist or is not selected the return value is false. 148 */ trackSelected(unsigned int track)149 inline bool trackSelected(unsigned int track) { 150 return (m_signal.trackSelected(track)); 151 } 152 153 /** 154 * Returns an array of indices of currently selected tracks. 155 */ 156 const QVector<unsigned int> selectedTracks(); 157 158 /** 159 * Returns an array of indices of all present tracks. 160 */ 161 const QVector<unsigned int> allTracks(); 162 163 /** 164 * Saves the signal to a file with a given resolution. If the file 165 * already exists, it will be overwritten. 166 * @param url URL with the name of the file to be saved. 167 * @param selection if true, only the selected range will be saved 168 * @return zero if succeeded or negative error code 169 */ 170 int save(const QUrl &url, bool selection); 171 172 /** 173 * Deletes a range of samples and creates an undo action. 174 * @param offset index of the first sample 175 * @param length number of samples 176 * @param track_list a list of tracks to be affected 177 * @return true if successful or nothing to do, false if not enough 178 * memory for undo 179 */ 180 bool deleteRange(sample_index_t offset, sample_index_t length, 181 const QVector<unsigned int> &track_list); 182 183 /** 184 * Deletes a range of samples and creates an undo action. Same as 185 * above, but affects all tracks. 186 * @param offset index of the first sample 187 * @param length number of samples 188 * @return true if successful or nothing to do, false if not enough 189 * memory for undo 190 */ 191 bool deleteRange(sample_index_t offset, sample_index_t length); 192 193 /** 194 * Inserts space at a given position and creates an undo action. 195 * @param offset position of the first sample to insert 196 * @param length number of samples 197 * @param track_list a list of tracks to be affected 198 * @return true if successful or nothing to do, false if not enough 199 * memory for undo 200 */ 201 bool insertSpace(sample_index_t offset, sample_index_t length, 202 const QVector<unsigned int> &track_list); 203 204 /** 205 * Sets the current start and length of the selection to new values. 206 * @param offset index of the first sample 207 * @param length number of samples 208 */ 209 void selectRange(sample_index_t offset, sample_index_t length); 210 211 /** 212 * Inserts a new track with the size of the current signal after 213 * the last track. The same as <c>insertTrack(tracks())</c>. 214 */ 215 void appendTrack(); 216 217 /** 218 * Inserts a new track in the current signal. 219 * @param index position at which the new track will be 220 * inserted [0...tracks()] 221 */ 222 void insertTrack(unsigned int index); 223 224 /** 225 * Deletes a track from the current signal, including generation 226 * of an undo action. 227 * @param index the index of the track to be deleted [0...tracks()-1] 228 */ 229 void deleteTrack(unsigned int index); 230 231 /** 232 * Selects multiple tracks, all other tracks will be disabled. 233 * @param track_list list of track indices 234 */ 235 void selectTracks(QVector<unsigned int> &track_list); 236 237 /** 238 * Sets the selection flag of a track. 239 * @param track index of the track [0..N-1] 240 * @param select if true, the track will be enabled, 241 * if false it will be disabled 242 */ 243 void selectTrack(unsigned int track, bool select); 244 245 /** 246 * Opens an output stream for a track, starting at a specified sample 247 * position. 248 * @param mode specifies where and how to insert 249 * @param track index of the track. If the track does not exist, this 250 * function will fail and return 0 251 * @param left start of the input (only useful in insert and 252 * overwrite mode) 253 * @param right end of the input (only useful with overwrite mode) 254 * @see InsertMode 255 */ 256 inline Kwave::Writer *openWriter(Kwave::InsertMode mode, 257 unsigned int track, 258 sample_index_t left = 0, sample_index_t right = 0) 259 { 260 return m_signal.openWriter(mode, track, left, right); 261 } 262 263 /** 264 * Opens a stream for reading samples. If the last position 265 * is omitted, the value SAMPLE_INDEX_MAX will be used. 266 * @param mode a reader mode, see SampleReader::Mode 267 * @param track index of the track. If the track does not exist, this 268 * function will fail and return 0 269 * @param left first offset to be read (default = 0) 270 * @param right last position to read (default = SAMPLE_INDEX_MAX) 271 */ 272 inline Kwave::SampleReader *openReader(Kwave::ReaderMode mode, 273 unsigned int track, 274 sample_index_t left = 0, sample_index_t right = SAMPLE_INDEX_MAX) 275 { 276 return m_signal.openReader(mode, track, left, right); 277 } 278 279 280 /** 281 * Get a list of stripes that matches a given range of samples 282 * @param track_list list with indices of tracks for selecting 283 * @param left offset of the first sample 284 * @param right offset of the last sample (default = SAMPLE_INDEX_MAX) 285 * @return a list with lists of stripes that cover the given range 286 * between left and right 287 */ 288 QList<Kwave::Stripe::List> stripes( 289 const QVector<unsigned int> &track_list, 290 sample_index_t left = 0, 291 sample_index_t right = SAMPLE_INDEX_MAX); 292 293 /** 294 * Merge a list of stripes into the signal. 295 * @note this operation works without undo! 296 * @param stripes list of stripe list (multi track) 297 * @param track_list list with indices of tracks for selecting 298 * @return true if succeeded, false if failed 299 */ 300 bool mergeStripes(const QList<Kwave::Stripe::List> &stripes, 301 const QVector<unsigned int> &track_list); 302 303 /** Returns a reference to the undo manager */ undoManager()304 inline Kwave::UndoManager &undoManager() { return m_undo_manager; } 305 306 /** Returns true if undo/redo is currently enabled */ undoEnabled()307 inline bool undoEnabled() const { return m_undo_enabled; } 308 309 /** Return true if undo is possible */ canUndo()310 inline bool canUndo() const { 311 return !m_undo_buffer.isEmpty() && undoEnabled(); 312 } 313 314 /** Return true if redo is possible */ canRedo()315 inline bool canRedo() const { 316 return !m_redo_buffer.isEmpty() && undoEnabled(); 317 } 318 319 /** 320 * Enables undo and redo. If undo/redo is already enabled, nothing 321 * will be done. 322 */ 323 void enableUndo(); 324 325 /** 326 * Disables undo and redo. If undo/redo was enabled, all undo data 327 * will be discarded in order to avoid trouble when modifications 328 * are done while undo is of. 329 * @note No modifications should be performed while undo is off! 330 */ 331 void disableUndo(); 332 333 /** 334 * Sets a complete set of file info, including undo information 335 * @param new_info a new FileInfo 336 * @param with_undo if true, store undo information 337 */ 338 void setFileInfo(const Kwave::FileInfo &new_info, bool with_undo); 339 340 /** 341 * add a new label, without undo 342 * @param pos position of the label [samples] 343 * @param name the name of the label 344 * @return a newly created label instance 345 */ 346 Kwave::Label addLabel(sample_index_t pos, const QString &name); 347 348 /** 349 * delete an existing label 350 * @param index the index of the label [0...N-1] 351 * @param with_undo if true, create undo info 352 */ 353 void deleteLabel(int index, bool with_undo); 354 355 /** 356 * modify an existing label at a given index 357 * (always without undo) 358 * @param index the index of the label [0...N-1] 359 * @param pos position of the label [samples] 360 * @param name the name of the label 361 * @param with_undo if true, create undo info 362 * @return true if succeeded, false if the index is out of range or if 363 * the new position is already occupied by an existing label 364 */ 365 bool modifyLabel(int index, sample_index_t pos, const QString &name, 366 bool with_undo); 367 368 /** 369 * Returns the index of a label, counting from zero 370 * @param label reference to a Label 371 * @return index [0...N-1] or -1 if label is a null pointer or not found 372 */ 373 int labelIndex(const Kwave::Label &label) const; 374 375 /** 376 * returns the label at a given exact position 377 * @param pos position of the label [samples] 378 * @return valid label at the position or null label if not found 379 */ 380 Kwave::Label findLabel(sample_index_t pos); 381 382 /** 383 * Retrieves the list of meta data objects, mutable 384 * @return list with all MetaData objects 385 */ metaData()386 Kwave::MetaDataList &metaData() { return m_meta_data; } 387 388 /** 389 * Retrieves the list of meta data objects, const 390 * @return reference to the list of all MetaData objects 391 */ metaData()392 const Kwave::MetaDataList &metaData() const { return m_meta_data; } 393 394 /** 395 * Merges a list of meta data items 396 * @param meta_data the meta data to merge 397 */ 398 void mergeMetaData(const Kwave::MetaDataList &meta_data); 399 400 /** 401 * Returns the uuid of a track 402 * @param track index of the track [0...tracks-1] 403 * @return the QUuid of the track or a "null" uuid if the track 404 * does not exist 405 */ uuidOfTrack(unsigned int track)406 QUuid uuidOfTrack(unsigned int track) { 407 return m_signal.uuidOfTrack(track); 408 } 409 410 /** 411 * assigns a new parent widget, to be used for messages 412 * @param new_parent pointer to a QWidget 413 */ setParentWidget(QWidget * new_parent)414 inline void setParentWidget(QWidget *new_parent) { 415 m_parent_widget = new_parent; 416 } 417 418 signals: 419 420 /** 421 * Signals a change in the range of selected samples. 422 * @param offset index of the first selected sample 423 * @param length number of selected samples 424 */ 425 void sigSelectionChanged(sample_index_t offset, sample_index_t length); 426 427 /** 428 * Signals that a track has been inserted. 429 * @param index position of the new track [0...tracks()-1] 430 * @param track reference to the new track 431 */ 432 void sigTrackInserted(unsigned int index, Kwave::Track *track); 433 434 /** 435 * Signals that a track has been deleted. 436 * @param index position of the deleted track [0...tracks()-1] 437 * @param track reference to the new track 438 */ 439 void sigTrackDeleted(unsigned int index, Kwave::Track *track); 440 441 /** 442 * Signals that the selection of one of the tracks has changed 443 * @param enabled state of the track, true=selected 444 */ 445 void sigTrackSelectionChanged(bool enabled); 446 447 /** 448 * Emitted if samples have been inserted into a track. This implies 449 * a modification of the inserted data, so no extra sigSamplesModified 450 * is emitted. 451 * @param track index of the track 452 * @param offset position from which the data was inserted 453 * @param length number of samples inserted 454 * @see sigSamplesModified 455 */ 456 void sigSamplesInserted(unsigned int track, sample_index_t offset, 457 sample_index_t length); 458 459 /** 460 * Emitted if samples have been removed from a track. 461 * @param track index of the track 462 * @param offset position from which the data was removed 463 * @param length number of samples deleted 464 */ 465 void sigSamplesDeleted(unsigned int track, sample_index_t offset, 466 sample_index_t length); 467 468 /** 469 * Emitted if samples within a track have been modified. 470 * @param track index of the track 471 * @param offset position from which the data was modified 472 * @param length number of samples modified 473 */ 474 void sigSamplesModified(unsigned int track, sample_index_t offset, 475 sample_index_t length); 476 477 /** 478 * Emitted whenever meta data has changed, after some operation 479 * @param meta the current meta data 480 */ 481 void sigMetaDataChanged(Kwave::MetaDataList meta); 482 483 /** 484 * Emitted if the state or description of undo/redo has changed. If 485 * undo or redo is unavailable the description will be zero. 486 * @see emitUndoRedoInfo 487 */ 488 void sigUndoRedoInfo(const QString &undo, const QString &redo); 489 490 /** 491 * Emitted if the signal changes from non-modified to modified 492 * state or vice-versa. 493 */ 494 void sigModified(); 495 496 public slots: 497 498 /** 499 * Un-does the last action if possible. 500 */ 501 void undo(); 502 503 /** 504 * re-does the last undone action. 505 */ 506 void redo(); 507 508 private slots: 509 510 /** 511 * Connected to the signal's sigTrackInserted. 512 * @param index numeric index of the inserted track 513 * @param track reference to the track that has been inserted 514 * @see Signal::sigTrackInserted 515 * @internal 516 */ 517 void slotTrackInserted(unsigned int index, Kwave::Track *track); 518 519 /** 520 * Connected to the signal's sigTrackInserted. 521 * @param index numeric index of the inserted track 522 * @param track reference to the track that has been deleted 523 * @see Signal::sigTrackDeleted 524 * @internal 525 */ 526 void slotTrackDeleted(unsigned int index, Kwave::Track *track); 527 528 /** 529 * Connected to the signal's sigSamplesInserted. 530 * @param track index of the source track [0...tracks-1] 531 * @param offset position from which the data was inserted 532 * @param length number of samples inserted 533 * @see Signal::sigSamplesInserted 534 * @internal 535 */ 536 void slotSamplesInserted(unsigned int track, sample_index_t offset, 537 sample_index_t length); 538 539 /** 540 * Connected to the signal's sigSamplesDeleted. 541 * @param track index of the source track [0...tracks-1] 542 * @param offset position from which the data was removed 543 * @param length number of samples deleted 544 * @see Signal::sigSamplesDeleted 545 * @internal 546 */ 547 void slotSamplesDeleted(unsigned int track, sample_index_t offset, 548 sample_index_t length); 549 550 /** 551 * Connected to the signal's sigSamplesModified 552 * @param track index of the source track [0...tracks-1] 553 * @param offset position from which the data was modified 554 * @param length number of samples modified 555 * @see Signal::sigSamplesModified 556 * @internal 557 */ 558 void slotSamplesModified(unsigned int track, sample_index_t offset, 559 sample_index_t length); 560 561 /** 562 * Closes an undo transaction or recurses the current recursion level 563 * of nested undo transactions. 564 */ 565 void closeUndoTransaction(); 566 567 /** 568 * Determines the description of undo and redo actions and emits 569 * a sigUndoRedoInfo. If undo or redo is currently not available, 570 * the descriptions will be zero-length. If an action is available 571 * but does not have a description, the description will be set 572 * to "last action". 573 * @see sigUndoRedoInfo 574 */ 575 void emitUndoRedoInfo(); 576 577 protected: 578 579 friend class Kwave::UndoInsertAction; 580 581 /** 582 * Deletes a range of samples. 583 * @note only for internal usage in the UndoInsertAction! 584 * @param track index of the track 585 * @param offset index of the first sample 586 * @param length number of samples 587 * @see Signal::deleteRange 588 */ deleteRange(unsigned int track,sample_index_t offset,sample_index_t length)589 inline void deleteRange(unsigned int track, sample_index_t offset, 590 sample_index_t length) 591 { 592 m_signal.deleteRange(track, offset, length); 593 } 594 595 protected: 596 597 friend class MultiTrackWriter; 598 friend class PlaybackController; 599 friend class PluginManager; 600 friend class MainWidget; 601 friend class UndoTransactionGuard; 602 603 /** 604 * Tries to free memory for a new undo action and stores all needed 605 * data if successful. 606 * @param action UndoAction to that is to be registered 607 * @return true if the action is allowed, false if the user has 608 * chosen to abort the operation if the memory limit of 609 * the undo buffer would be exceeded. The return value 610 * will also be false if the action is null. 611 * @note If undo is currently not enabled, the passed UndoAction 612 * will be ignored and not freed, the return value will 613 * be false. So it is safer not to call this function if 614 * undo is not enabled. 615 */ 616 bool registerUndoAction(Kwave::UndoAction *action); 617 618 /** 619 * Saves undo data for deleting a range of samples from a list 620 * of tracks. 621 * @param track_list list of indices of tracks 622 * @param offset first sample position to delete 623 * @param length number of samples to delete 624 * @return true if successful, false if out of memory or aborted 625 */ 626 bool saveUndoDelete(QVector<unsigned int> &track_list, 627 sample_index_t offset, sample_index_t length); 628 629 /** 630 * Aborts an undo transaction by deleting all of it's undo actions. 631 */ 632 void abortUndoTransaction(); 633 634 /** 635 * Starts an undo transaction or enters a currently running transaction 636 * recursively. 637 * @param name the name of the transaction. Will be ignored if there 638 * already is an active transaction (optional) 639 */ 640 void startUndoTransaction(const QString &name = QString()); 641 642 /** 643 * Removes all undo and redo transactions. 644 * @note must not be called if an undo transaction is currently active! 645 */ 646 void flushUndoBuffers(); 647 648 /** 649 * Removes all redo transactions. 650 */ 651 void flushRedoBuffer(); 652 653 /** 654 * Sets the modified flag to a new value if m_modified_enabled is 655 * true, otherwise it will be ignored. 656 */ 657 void setModified(bool mod); 658 659 /** returns the associated parent widget, to be used for messages */ parentWidget()660 QWidget *parentWidget() const { return m_parent_widget; } 661 662 private: 663 664 /** 665 * Ask the user if he wants to continue without undo, maybe 666 * registering an undo action has failed due to out-of-memory. 667 * @return true if it is ok, false if the user doesn't want to. 668 */ 669 bool continueWithoutUndo(); 670 671 /** 672 * Returns the amount of memory currently used for undo + redo. 673 */ 674 qint64 usedUndoRedoMemory(); 675 676 /** 677 * Makes sure that enough memory for a following undo (or redo) action 678 * is available. If necessary, it deletes old undo transactions and if 679 * still no enough, it also removes old redo transactions. 680 * @param needed the amount of memory that should be free afterwards 681 */ 682 void freeUndoMemory(qint64 needed); 683 684 /** 685 * Enables changes of the modified flag. 686 * @param en new value for m_modified_enabled 687 */ 688 void enableModifiedChange(bool en); 689 690 /** saves the current sample and track selection */ 691 void rememberCurrentSelection(); 692 693 /** 694 * Check whether the selection has changed since the start of 695 * the last undo and create a new undo action if the selection 696 * has been modified (e.g. manually) 697 */ 698 void checkSelectionChange(); 699 700 private: 701 702 /** Parent widget, used for showing messages */ 703 QWidget *m_parent_widget; 704 705 /** true if the signal is closed */ 706 bool m_closed; 707 708 /** true if the signal is completely empty */ 709 bool m_empty; 710 711 /** true if the signal has been modified */ 712 bool m_modified; 713 714 /** 715 * If set to true, prevents the modified flag from changes. Useful 716 * to prevent setting the modified flag during file load and creation, 717 * or if the change to the non-modified state through undo operations 718 * is no longer possible. 719 */ 720 bool m_modified_enabled; 721 722 /** signal with multiple tracks */ 723 Kwave::Signal m_signal; 724 725 /** the current selection */ 726 Kwave::Selection m_selection; 727 728 /** the last selection (stored in undo) */ 729 Kwave::Selection m_last_selection; 730 731 /** the last track selection (stored in undo) */ 732 QVector <unsigned int> m_last_track_selection; 733 734 /** 735 * Last known length of the signal. This will be used if a track is 736 * added to an empty signal and prevents from the creation of a 737 * completely empty new signal. 738 */ 739 sample_index_t m_last_length; 740 741 /** the controller for handling of playback */ 742 Kwave::PlaybackController m_playback_controller; 743 744 /** flag for "undo enabled" */ 745 bool m_undo_enabled; 746 747 /** fifo used for storing all undo transactions */ 748 QList<Kwave::UndoTransaction *> m_undo_buffer; 749 750 /** fifo for storing all redo transactions */ 751 QList<Kwave::UndoTransaction *> m_redo_buffer; 752 753 /** the current undo transaction */ 754 Kwave::UndoTransaction *m_undo_transaction; 755 756 /** level of nested undo transactions */ 757 unsigned int m_undo_transaction_level; 758 759 /** mutex for locking undo transactions */ 760 QRecursiveMutex m_undo_transaction_lock; 761 762 /** Manager for undo/redo actions */ 763 Kwave::UndoManager m_undo_manager; 764 765 /** 766 * meta data of the signal 767 * @see class MetaData 768 */ 769 Kwave::MetaDataList m_meta_data; 770 771 }; 772 } 773 774 #endif /* SIGNAL_MANAGER_H */ 775 776 //*************************************************************************** 777 //*************************************************************************** 778