summaryrefslogtreecommitdiffstats
path: root/raul
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2008-05-23 03:41:45 +0000
committerDavid Robillard <d@drobilla.net>2008-05-23 03:41:45 +0000
commit6ebefb4c8b523ecac35b7440907ef9e57d0154f0 (patch)
treecb2f25b531b9b38a642767a7fd21c5f285ca4623 /raul
parent264ce503aebaa87d275f23d1ea1a33034083b190 (diff)
downloadraul-6ebefb4c8b523ecac35b7440907ef9e57d0154f0.tar.gz
raul-6ebefb4c8b523ecac35b7440907ef9e57d0154f0.tar.bz2
raul-6ebefb4c8b523ecac35b7440907ef9e57d0154f0.zip
Merge improvemennts to MIDI stuff from Ardour.
git-svn-id: http://svn.drobilla.net/lad/raul@1227 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'raul')
-rw-r--r--raul/RingBuffer.hpp114
-rw-r--r--raul/SMFReader.hpp43
-rw-r--r--raul/midi_names.h94
3 files changed, 162 insertions, 89 deletions
diff --git a/raul/RingBuffer.hpp b/raul/RingBuffer.hpp
index 4098a2f..dff1464 100644
--- a/raul/RingBuffer.hpp
+++ b/raul/RingBuffer.hpp
@@ -1,5 +1,5 @@
/* This file is part of Raul.
- * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
+ * Copyright (C) 2007-2008 Dave Robillard <http://drobilla.net>
*
* Raul is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
@@ -19,6 +19,7 @@
#define RAUL_RING_BUFFER_HPP
#include <cassert>
+#include <iostream>
#include <glib.h>
namespace Raul {
@@ -62,7 +63,7 @@ public:
if (w > r) {
return ((r - w + _size) % _size) - 1;
- } else if(w < r) {
+ } else if (w < r) {
return (r - w) - 1;
} else {
return _size - 1;
@@ -83,20 +84,65 @@ public:
size_t capacity() const { return _size; }
+ size_t peek(size_t size, T* dst);
+ bool full_peek(size_t size, T* dst);
+
size_t read(size_t size, T* dst);
- void write(size_t size, const T* src);
-
bool full_read(size_t size, T* dst);
+ bool skip(size_t size);
+
+ void write(size_t size, const T* src);
+
protected:
- mutable gint _write_ptr;
- mutable gint _read_ptr;
+ mutable int _write_ptr;
+ mutable int _read_ptr;
size_t _size; ///< Size (capacity) in bytes
- T* _buf; ///< size, event, size, event...
+ T* _buf; ///< size, event, size, event...
};
+/** Peek at the ringbuffer (read w/o advancing read pointer).
+ *
+ * Note that a full read may not be done if the data wraps around.
+ * Caller must check return value and call again if necessary, or use the
+ * full_peek method which does this automatically.
+ */
+template<typename T>
+size_t
+RingBuffer<T>::peek(size_t size, T* dst)
+{
+ const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+
+ const size_t read_size = (priv_read_ptr + size < _size)
+ ? size
+ : _size - priv_read_ptr;
+
+ memcpy(dst, &_buf[priv_read_ptr], read_size);
+
+ return read_size;
+}
+
+
+template<typename T>
+bool
+RingBuffer<T>::full_peek(size_t size, T* dst)
+{
+ if (read_space() < size) {
+ return false;
+ }
+
+ const size_t read_size = peek(size, dst);
+
+ if (read_size < size) {
+ peek(size - read_size, dst + read_size);
+ }
+
+ return true;
+}
+
+
/** Read from the ringbuffer.
*
* Note that a full read may not be done if the data wraps around.
@@ -122,6 +168,40 @@ RingBuffer<T>::read(size_t size, T* dst)
template<typename T>
+bool
+RingBuffer<T>::full_read(size_t size, T* dst)
+{
+ if (read_space() < size) {
+ return false;
+ }
+
+ const size_t read_size = read(size, dst);
+
+ if (read_size < size) {
+ read(size - read_size, dst + read_size);
+ }
+
+ return true;
+}
+
+
+template<typename T>
+bool
+RingBuffer<T>::skip(size_t size)
+{
+ if (read_space() < size) {
+ std::cerr << "WARNING: Attempt to skip past end of MIDI ring buffer" << std::endl;
+ return false;
+ }
+
+ const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+ g_atomic_int_set(&_read_ptr, (priv_read_ptr + size) % _size);
+
+ return true;
+}
+
+
+template<typename T>
inline void
RingBuffer<T>::write(size_t size, const T* src)
{
@@ -129,33 +209,17 @@ RingBuffer<T>::write(size_t size, const T* src)
if (priv_write_ptr + size <= _size) {
memcpy(&_buf[priv_write_ptr], src, size);
- g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
+ g_atomic_int_set(&_write_ptr, (priv_write_ptr + size) % _size);
} else {
const size_t this_size = _size - priv_write_ptr;
assert(this_size < size);
assert(priv_write_ptr + this_size <= _size);
memcpy(&_buf[priv_write_ptr], src, this_size);
memcpy(&_buf[0], src+this_size, size - this_size);
- g_atomic_int_set(&_write_ptr, size - this_size);
+ g_atomic_int_set(&_write_ptr, size - this_size);
}
}
-
-template<typename T>
-bool
-RingBuffer<T>::full_read(size_t size, T* dst)
-{
- if (read_space() < size)
- return false;
-
- const size_t read_size = read(size, dst);
-
- if (read_size < size)
- read(size - read_size, dst + read_size);
-
- return true;
-}
-
} // namespace Raul
diff --git a/raul/SMFReader.hpp b/raul/SMFReader.hpp
index 7ce6f5b..1bd1f0d 100644
--- a/raul/SMFReader.hpp
+++ b/raul/SMFReader.hpp
@@ -32,39 +32,48 @@ namespace Raul {
*/
class SMFReader {
public:
- SMFReader();
+ class PrematureEOF : public std::exception {
+ const char* what() const throw() { return "Unexpected end of file"; }
+ };
+ class CorruptFile : public std::exception {
+ const char* what() const throw() { return "Corrupted file"; }
+ };
+ class UnsupportedTime : public std::exception {
+ const char* what() const throw() { return "Unsupported time stamp type (SMPTE)"; }
+ };
+
+ SMFReader(const std::string filename="");
~SMFReader();
- bool open(const std::string& filename);
+ bool open(const std::string& filename) throw (std::logic_error, UnsupportedTime);
bool seek_to_track(unsigned track) throw (std::logic_error);
- TimeUnit unit() const { return _unit; }
uint16_t type() const { return _type; }
uint16_t ppqn() const { return _ppqn; }
size_t num_tracks() { return _num_tracks; }
- int read_event(size_t buf_len,
- uint8_t* buf,
- uint32_t* ev_size,
- TimeStamp* ev_delta_time) throw (std::logic_error);
+ int read_event(size_t buf_len,
+ uint8_t* buf,
+ uint32_t* ev_size,
+ uint32_t* ev_delta_time)
+ throw (std::logic_error, PrematureEOF, CorruptFile);
void close();
+
+ static uint32_t read_var_len(FILE* fd) throw (PrematureEOF);
protected:
/** size of SMF header, including MTrk chunk header */
static const uint32_t HEADER_SIZE = 22;
- uint32_t read_var_len() const;
-
- std::string _filename;
- FILE* _fd;
- TimeUnit _unit;
- uint16_t _type;
- uint16_t _ppqn;
- uint16_t _num_tracks;
- uint32_t _track;
- uint32_t _track_size;
+ std::string _filename;
+ FILE* _fd;
+ uint16_t _type;
+ uint16_t _ppqn;
+ uint16_t _num_tracks;
+ uint32_t _track;
+ uint32_t _track_size;
};
diff --git a/raul/midi_names.h b/raul/midi_names.h
index 1b98f9a..114c299 100644
--- a/raul/midi_names.h
+++ b/raul/midi_names.h
@@ -81,69 +81,69 @@ inline static const char* midi_name(uint8_t status)
return "Reset"; break;
case MIDI_CTL_MSB_BANK:
- return "Bank Selection"; break;
+ return "Bank Select (Coarse)"; break;
case MIDI_CTL_MSB_MODWHEEL:
- return "Modulation"; break;
+ return "Modulation (Coarse)"; break;
case MIDI_CTL_MSB_BREATH:
- return "Breath"; break;
+ return "Breath (Coarse)"; break;
case MIDI_CTL_MSB_FOOT:
- return "Foot"; break;
+ return "Foot (Coarse)"; break;
case MIDI_CTL_MSB_PORTAMENTO_TIME:
- return "Portamento Time"; break;
+ return "Portamento Time (Coarse)"; break;
case MIDI_CTL_MSB_DATA_ENTRY:
- return "Data Entry"; break;
+ return "Data Entry (Coarse)"; break;
case MIDI_CTL_MSB_MAIN_VOLUME:
- return "Main Volume"; break;
+ return "Main Volume (Coarse)"; break;
case MIDI_CTL_MSB_BALANCE:
- return "Balance"; break;
+ return "Balance (Coarse)"; break;
case MIDI_CTL_MSB_PAN:
- return "Panpot"; break;
+ return "Pan (Coarse)"; break;
case MIDI_CTL_MSB_EXPRESSION:
- return "Expression"; break;
+ return "Expression (Coarse)"; break;
case MIDI_CTL_MSB_EFFECT1:
- return "Effect1"; break;
+ return "Effect 1 (Coarse)"; break;
case MIDI_CTL_MSB_EFFECT2:
- return "Effect2"; break;
+ return "Effect 2 (Coarse)"; break;
case MIDI_CTL_MSB_GENERAL_PURPOSE1:
- return "General Purpose 1"; break;
+ return "General Purpose 1 (Coarse)"; break;
case MIDI_CTL_MSB_GENERAL_PURPOSE2:
- return "General Purpose 2"; break;
+ return "General Purpose 2 (Coarse)"; break;
case MIDI_CTL_MSB_GENERAL_PURPOSE3:
- return "General Purpose 3"; break;
+ return "General Purpose 3 (Coarse)"; break;
case MIDI_CTL_MSB_GENERAL_PURPOSE4:
- return "General Purpose 4"; break;
+ return "General Purpose 4 (Coarse)"; break;
case MIDI_CTL_LSB_BANK:
- return "Bank Selection"; break;
+ return "Bank Select (Fine)"; break;
case MIDI_CTL_LSB_MODWHEEL:
- return "Modulation"; break;
+ return "Modulation (Fine)"; break;
case MIDI_CTL_LSB_BREATH:
- return "Breath"; break;
+ return "Breath (Fine)"; break;
case MIDI_CTL_LSB_FOOT:
- return "Foot"; break;
+ return "Foot (Fine)"; break;
case MIDI_CTL_LSB_PORTAMENTO_TIME:
- return "Portamento Time"; break;
+ return "Portamento Time (Fine)"; break;
case MIDI_CTL_LSB_DATA_ENTRY:
- return "Data Entry"; break;
+ return "Data Entry (Fine)"; break;
case MIDI_CTL_LSB_MAIN_VOLUME:
- return "Main Volume"; break;
+ return "Main Volume (Fine)"; break;
case MIDI_CTL_LSB_BALANCE:
- return "Balance"; break;
+ return "Balance (Fine)"; break;
case MIDI_CTL_LSB_PAN:
- return "Panpot"; break;
+ return "Pan (Fine)"; break;
case MIDI_CTL_LSB_EXPRESSION:
- return "Expression"; break;
+ return "Expression (Fine)"; break;
case MIDI_CTL_LSB_EFFECT1:
- return "Effect1"; break;
+ return "Effect 1 (Fine)"; break;
case MIDI_CTL_LSB_EFFECT2:
- return "Effect2"; break;
+ return "Effect 2 (Fine)"; break;
case MIDI_CTL_LSB_GENERAL_PURPOSE1:
- return "General Purpose 1"; break;
+ return "General Purpose 1 (Fine)"; break;
case MIDI_CTL_LSB_GENERAL_PURPOSE2:
- return "General Purpose 2"; break;
+ return "General Purpose 2 (Fine)"; break;
case MIDI_CTL_LSB_GENERAL_PURPOSE3:
- return "General Purpose 3"; break;
+ return "General Purpose 3 (Fine)"; break;
case MIDI_CTL_LSB_GENERAL_PURPOSE4:
- return "General Purpose 4"; break;
+ return "General Purpose 4 (Fine)"; break;
case MIDI_CTL_SUSTAIN:
return "Sustain Pedal"; break;
case MIDI_CTL_PORTAMENTO:
@@ -157,25 +157,25 @@ inline static const char* midi_name(uint8_t status)
case MIDI_CTL_HOLD2:
return "Hold2"; break;
case MIDI_CTL_SC1_SOUND_VARIATION:
- return "SC1 Sound Variation"; break;
+ return "Sound Variation"; break;
case MIDI_CTL_SC2_TIMBRE:
- return "SC2 Timbre"; break;
+ return "Sound Timbre"; break;
case MIDI_CTL_SC3_RELEASE_TIME:
- return "SC3 Release Time"; break;
+ return "Sound Release Time"; break;
case MIDI_CTL_SC4_ATTACK_TIME:
- return "SC4 Attack Time"; break;
+ return "Sound Attack Time"; break;
case MIDI_CTL_SC5_BRIGHTNESS:
- return "SC5 Brightness"; break;
+ return "Sound Brightness"; break;
case MIDI_CTL_SC6:
- return "SC6"; break;
+ return "Sound Control 6"; break;
case MIDI_CTL_SC7:
- return "SC7"; break;
+ return "Sound Control 7"; break;
case MIDI_CTL_SC8:
- return "SC8"; break;
+ return "Sound Control 8"; break;
case MIDI_CTL_SC9:
- return "SC9"; break;
+ return "Sound Control 9"; break;
case MIDI_CTL_SC10:
- return "SC10"; break;
+ return "Sound Control 10"; break;
case MIDI_CTL_GENERAL_PURPOSE5:
return "General Purpose 5"; break;
case MIDI_CTL_GENERAL_PURPOSE6:
@@ -187,15 +187,15 @@ inline static const char* midi_name(uint8_t status)
case MIDI_CTL_PORTAMENTO_CONTROL:
return "Portamento Control"; break;
case MIDI_CTL_E1_REVERB_DEPTH:
- return "E1 Reverb Depth"; break;
+ return "Reverb Depth"; break;
case MIDI_CTL_E2_TREMOLO_DEPTH:
- return "E2 Tremolo Depth"; break;
+ return "Tremolo Depth"; break;
case MIDI_CTL_E3_CHORUS_DEPTH:
- return "E3 Chorus Depth"; break;
+ return "Chorus Depth"; break;
case MIDI_CTL_E4_DETUNE_DEPTH:
- return "E4 Detune Depth"; break;
+ return "Detune Depth"; break;
case MIDI_CTL_E5_PHASER_DEPTH:
- return "E5 Phaser Depth"; break;
+ return "Phaser Depth"; break;
case MIDI_CTL_DATA_INCREMENT:
return "Data Increment"; break;
case MIDI_CTL_DATA_DECREMENT: