summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2007-04-02 00:26:21 +0000
committerDavid Robillard <d@drobilla.net>2007-04-02 00:26:21 +0000
commita23b21908e4d0fab277a9f6f7d5a3b5a69746740 (patch)
treea12085c9eb5873d48ecf08ffe030fa2b459d6ef6
parent69559bddc0ae41f1f81241d92675009f86fa79b1 (diff)
downloadraul-a23b21908e4d0fab277a9f6f7d5a3b5a69746740.tar.gz
raul-a23b21908e4d0fab277a9f6f7d5a3b5a69746740.tar.bz2
raul-a23b21908e4d0fab277a9f6f7d5a3b5a69746740.zip
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
-rw-r--r--raul/List.h46
-rw-r--r--raul/TimeSlice.h2
-rw-r--r--src/SMFReader.cpp15
-rw-r--r--tests/list_test.cpp81
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<T>* elem); // realtime safe
void push_back(T& elem); // NOT realtime safe
+ void append(List<T>& list);
+
void clear();
/// Valid only in the write thread
@@ -235,6 +237,48 @@ List<T>::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 <typename T>
+void
+List<T>::append(List<T>& list)
+{
+ ListNode<T>* const my_head = _head.get();
+ ListNode<T>* const my_tail = _tail.get();
+ ListNode<T>* const other_head = list._head.get();
+ ListNode<T>* 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
@@ -97,6 +97,19 @@ SMFReader::open(const string& filename)
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;
fread(&type_be, 2, 1, _fd);
@@ -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<int>::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<int>::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<int>::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<int>::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<int>::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<int>::iterator i = l.begin(); i != l.end(); ++i) {
cout << *i << endl;
}
@@ -93,9 +93,76 @@ int main()
List<int> r;
r.push_back(new ListNode<int>(9));
r.erase(r.begin());
- std::cerr << "Should not see ANY numbers:\n";
+ cout << "Should not see ANY numbers:\n";
for (List<int>::iterator i = r.begin(); i != r.end(); ++i) {
cout << *i << endl;
}
+
+ cout << "\n\nTesting appending to an empty list:\n";
+ l.clear();
+
+ List<int> l2;
+ l2.push_back(new ListNode<int>(1));
+ l2.push_back(new ListNode<int>(2));
+ l2.push_back(new ListNode<int>(3));
+ l2.push_back(new ListNode<int>(4));
+
+ cout << "l1:\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ cout << "l2:\n";
+ for (List<int>::iterator i = l2.begin(); i != l2.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ l.append(l2);
+ cout << "l1.append(l2):\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ cout << "\n\nAppending non-empty lists:\n";
+ l2.push_back(new ListNode<int>(5));
+ l2.push_back(new ListNode<int>(6));
+ l2.push_back(new ListNode<int>(7));
+ l2.push_back(new ListNode<int>(8));
+
+ cout << "l1:\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ cout << "l2:\n";
+ for (List<int>::iterator i = l2.begin(); i != l2.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ l.append(l2);
+ cout << "l1.append(l2):\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
+
+ cout << "\n\nAppending an empty list:\n";
+
+ cout << "l1:\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ cout << "l2:\n";
+ for (List<int>::iterator i = l2.begin(); i != l2.end(); ++i) {
+ cout << *i << endl;
+ }
+
+ l.append(l2);
+ cout << "l1.append(l2):\n";
+ for (List<int>::iterator i = l.begin(); i != l.end(); ++i) {
+ cout << *i << endl;
+ }
+
return 0;
}