From a23b21908e4d0fab277a9f6f7d5a3b5a69746740 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 2 Apr 2007 00:26:21 +0000 Subject: List appending. Make SMFReader abort gracefully on non-SMF files. git-svn-id: http://svn.drobilla.net/lad/raul@389 a436a847-0d15-0410-975c-d299462d15a1 --- raul/List.h | 46 +++++++++++++++++++++++++++++- raul/TimeSlice.h | 2 +- src/SMFReader.cpp | 15 +++++++++- tests/list_test.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 134 insertions(+), 10 deletions(-) diff --git a/raul/List.h b/raul/List.h index e7e2158..79748ba 100644 --- a/raul/List.h +++ b/raul/List.h @@ -55,7 +55,7 @@ private: -/** A realtime safe, (partially) thread safe doubly linked list. +/** A realtime safe, (partially) thread safe doubly-linked list. * * Elements can be added safely while another thread is reading the list. * Like a typical ringbuffer, this is single-reader single-writer threadsafe @@ -75,6 +75,8 @@ public: void push_back(ListNode* elem); // realtime safe void push_back(T& elem); // NOT realtime safe + void append(List& list); + void clear(); /// Valid only in the write thread @@ -235,6 +237,48 @@ List::push_back(T& elem) } +/** Append a list to this list. + * + * This operation is fast ( O(1) ). + * The appended list is not safe to use concurrently with this call. + * + * The appended list will be empty after this call. + * + * Thread safe (may be called while another thread is reading the list). + * Realtime safe. + */ +template +void +List::append(List& list) +{ + ListNode* const my_head = _head.get(); + ListNode* const my_tail = _tail.get(); + ListNode* const other_head = list._head.get(); + ListNode* const other_tail = list._tail.get(); + + // Appending to an empty list + if (my_head == NULL && my_tail == NULL) { + _head = other_head; + _tail = other_tail; + _size = list._size; + } else if (other_head != NULL && other_tail != NULL) { + + other_head->prev(my_tail); + + // FIXME: atomicity an issue? _size < true size is probably fine... + // no gurantee an iteration runs exactly size times though. verify/document this. + // assuming comment above that says tail is writer only, this is fine + my_tail->next(other_head); + _tail = other_tail; + _size += list.size(); + } + + list._head = NULL; + list._tail = NULL; + list._size = 0; +} + + /** Remove all elements equal to @val from the list. * * This function is realtime safe - it is the caller's responsibility to diff --git a/raul/TimeSlice.h b/raul/TimeSlice.h index dec91e5..0c8bab8 100644 --- a/raul/TimeSlice.h +++ b/raul/TimeSlice.h @@ -86,7 +86,7 @@ public: void set_bpm(double bpm) { _beat_rate = 60.0/bpm; - //update_beat_time(); + update_beat_time(); } inline Seconds beats_to_seconds(BeatTime beats) const { diff --git a/src/SMFReader.cpp b/src/SMFReader.cpp index 56232cf..a267e48 100644 --- a/src/SMFReader.cpp +++ b/src/SMFReader.cpp @@ -96,6 +96,19 @@ SMFReader::open(const string& filename) _fd = fopen(filename.c_str(), "r+"); if (_fd) { + // Read type (bytes 8..9) + fseek(_fd, 0, SEEK_SET); + char mthd[5]; + mthd[4] = '\0'; + fread(mthd, 1, 4, _fd); + if (strcmp(mthd, "MThd")) { + cerr << "File is not an SMF file, aborting." << endl; + fclose(_fd); + _fd = NULL; + return false; + } + + // Read type (bytes 8..9) fseek(_fd, 8, SEEK_SET); uint16_t type_be = 0; @@ -153,7 +166,7 @@ SMFReader::seek_to_track(unsigned track) if (!strcmp(id, "MTrk")) { ++track_pos; - std::cerr << "Found track " << track_pos << endl; + //std::cerr << "Found track " << track_pos << endl; } else { std::cerr << "Unknown chunk ID " << id << endl; } diff --git a/tests/list_test.cpp b/tests/list_test.cpp index faee491..133067b 100644 --- a/tests/list_test.cpp +++ b/tests/list_test.cpp @@ -33,7 +33,7 @@ int main() } } - std::cerr << "Removed 4 (by iterator)...\n"; + cout << "Removed 4 (by iterator)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -41,7 +41,7 @@ int main() /*l.remove(1); - std::cerr << "Removed 1 (head) (by value)...\n"; + cout << "Removed 1 (head) (by value)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -55,7 +55,7 @@ int main() } } - std::cerr << "Removed 2 (head) (by iterator)...\n"; + cout << "Removed 2 (head) (by iterator)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -63,7 +63,7 @@ int main() /*l.remove(5); - std::cerr << "Removed 5 (by value)...\n"; + cout << "Removed 5 (by value)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -71,7 +71,7 @@ int main() l.remove(8); - std::cerr << "Removed 8 (tail) (by value)...\n"; + cout << "Removed 8 (tail) (by value)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -84,7 +84,7 @@ int main() } } - std::cerr << "Removed 7 (tail) (by iterator)...\n"; + cout << "Removed 7 (tail) (by iterator)...\n"; for (List::iterator i = l.begin(); i != l.end(); ++i) { cout << *i << endl; } @@ -93,9 +93,76 @@ int main() List r; r.push_back(new ListNode(9)); r.erase(r.begin()); - std::cerr << "Should not see ANY numbers:\n"; + cout << "Should not see ANY numbers:\n"; for (List::iterator i = r.begin(); i != r.end(); ++i) { cout << *i << endl; } + + cout << "\n\nTesting appending to an empty list:\n"; + l.clear(); + + List l2; + l2.push_back(new ListNode(1)); + l2.push_back(new ListNode(2)); + l2.push_back(new ListNode(3)); + l2.push_back(new ListNode(4)); + + cout << "l1:\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + + cout << "l2:\n"; + for (List::iterator i = l2.begin(); i != l2.end(); ++i) { + cout << *i << endl; + } + + l.append(l2); + cout << "l1.append(l2):\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + + cout << "\n\nAppending non-empty lists:\n"; + l2.push_back(new ListNode(5)); + l2.push_back(new ListNode(6)); + l2.push_back(new ListNode(7)); + l2.push_back(new ListNode(8)); + + cout << "l1:\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + + cout << "l2:\n"; + for (List::iterator i = l2.begin(); i != l2.end(); ++i) { + cout << *i << endl; + } + + l.append(l2); + cout << "l1.append(l2):\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + + + cout << "\n\nAppending an empty list:\n"; + + cout << "l1:\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + + cout << "l2:\n"; + for (List::iterator i = l2.begin(); i != l2.end(); ++i) { + cout << *i << endl; + } + + l.append(l2); + cout << "l1.append(l2):\n"; + for (List::iterator i = l.begin(); i != l.end(); ++i) { + cout << *i << endl; + } + return 0; } -- cgit v1.2.1