fix (mostly) measure lines and click box text and meter markings
authorPaul Davis <paul@linuxaudiosystems.com>
Sat, 28 Jan 2006 13:33:54 +0000 (13:33 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Sat, 28 Jan 2006 13:33:54 +0000 (13:33 +0000)
git-svn-id: svn://localhost/trunk/ardour2@300 d708f5d6-7413-0410-9779-e7cbd77b26cf

14 files changed:
gtk2_ardour/ardour2_ui.rc
gtk2_ardour/canvas-simpleline.c
gtk2_ardour/editor.cc
gtk2_ardour/editor_actions.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_tempodisplay.cc
gtk2_ardour/gain_meter.cc
libs/ardour/ardour/destructive_filesource.h
libs/ardour/audiofilter.cc
libs/ardour/destructive_filesource.cc
libs/ardour/session_timefx.cc
libs/gtkmm2ext/click_box.cc
libs/gtkmm2ext/gtkmm2ext/click_box.h
libs/midi++2/mmc.cc

index 92a9cbb19a5f5f7f71f1d3fa6bb6eba9278fc266..90ecf53717e63db917429386d688e42b0096a888 100644 (file)
@@ -1709,7 +1709,7 @@ widget "*cTempoMarker" style "cTempoMarker"
 
 style "cMeasureLineBeat"
 {
-       fg[NORMAL] = { 0.51, 0.59, 0.51 }
+       fg[NORMAL] = { 0.51, 0.59, 0.87 }
         fg[ACTIVE] = { 0.98, 0, 0 }
 }
 widget "*cMeasureLineBeat" style "cMeasureLineBeat"
index 3aeee4b32ab7c0776f36bd5136b4f750ed618699..4ba3d6bc76f5ca692cff346b2775a0c2db086847 100644 (file)
@@ -287,6 +287,7 @@ gnome_canvas_simpleline_set_property (GObject      *object,
        case PROP_COLOR_RGBA:
                if (simpleline->color != g_value_get_uint(value)) {
                        simpleline->color = g_value_get_uint(value);
+                       UINT_TO_RGBA (simpleline->color, &simpleline->r, &simpleline->g, &simpleline->b, &simpleline->a);
                        update = TRUE;
                }
                break;
@@ -377,8 +378,8 @@ gnome_canvas_simpleline_render (GnomeCanvasItem *item,
                buf->is_bg = FALSE;
        }
 
-       // begin = MAX(simpleline->bbox_ulx,buf->rect.x0);
-       // end = MIN(simpleline->bbox_lrx,buf->rect.x1);
+       //begin = MAX(simpleline->bbox_ulx,buf->rect.x0);
+       //end = MIN(simpleline->bbox_lrx,buf->rect.x1);
        
        begin = simpleline->bbox_ulx;
        end = simpleline->bbox_lrx;
@@ -388,7 +389,7 @@ gnome_canvas_simpleline_render (GnomeCanvasItem *item,
                        PAINT_HORIZA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a, 
                                     begin, end, simpleline->bbox_uly);
                } else {
-                       PAINT_VERTA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a, 
+                       PAINT_VERTA(buf, simpleline->r, simpleline->g, simpleline->b, simpleline->a,
                                    begin, simpleline->bbox_uly, simpleline->bbox_lry);
                }
        }
index 5800888d0cfbb3d2c4e5e892196c00e99d491eca..d6b9f5b278c9e0f96aa0cc4fce216959a26e313d 100644 (file)
@@ -2121,19 +2121,37 @@ Editor::set_state (const XMLNode& node)
        if ((prop = node.property ("show-waveforms"))) {
                bool yn = (prop->value() == "yes");
                _show_waveforms = !yn;
-               set_show_waveforms (yn);
+               RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       /* do it twice to force the change */
+                       tact->set_active (!yn);
+                       tact->set_active (yn);
+               }
        }
 
        if ((prop = node.property ("show-waveforms-recording"))) {
                bool yn = (prop->value() == "yes");
                _show_waveforms_recording = !yn;
-               set_show_waveforms_recording (yn);
+               RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformsWhileRecording"));
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       /* do it twice to force the change */
+                       tact->set_active (!yn);
+                       tact->set_active (yn);
+               }
        }
        
        if ((prop = node.property ("show-measures"))) {
                bool yn = (prop->value() == "yes");
                _show_measures = !yn;
-               set_show_measures (yn);
+               RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
+               if (act) {
+                       RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
+                       /* do it twice to force the change */
+                       tact->set_active (!yn);
+                       tact->set_active (yn);
+               }
        }
 
        if ((prop = node.property ("follow-playhead"))) {
index 5f92c62bd721de3fc03a3ca501de3acbfe990453..e3dcfac15ad6c9cca3e83271763d72673bcb87f2 100644 (file)
@@ -324,8 +324,8 @@ Editor::register_actions ()
 
        ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformVisibility"), _("show waveforms"), mem_fun (*this, &Editor::toggle_waveform_visibility));
        ActionManager::register_toggle_action (editor_actions, X_("ToggleWaveformsWhileRecording"), _("show waveforms while recording"), mem_fun (*this, &Editor::toggle_waveforms_while_recording));
-       ActionManager::register_toggle_action (editor_actions, X_("ToggleMeasureVisibility"), _("show measures"), mem_fun (*this, &Editor::toggle_measure_visibility));
-
+       act = ActionManager::register_toggle_action (editor_actions, X_("ToggleMeasureVisibility"), _("show measures"), mem_fun (*this, &Editor::toggle_measure_visibility));
+       
        RadioAction::Group meter_falloff_group;
        RadioAction::Group meter_hold_group;
 
@@ -377,7 +377,7 @@ Editor::toggle_waveforms_while_recording ()
 void
 Editor::toggle_measure_visibility ()
 {
-       Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleWaveformVisibility"));
+       Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
        if (act) {
                Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
                set_show_measures (tact->get_active());
index 02271e24670f3a8583a8de4686e306a689af3ed6..75a026f92bd455d2dbb20878a2f54edddf11e14c 100644 (file)
@@ -94,6 +94,11 @@ Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
        case GDK_LEAVE_NOTIFY:
                track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy);
                break;
+       case GDK_KEY_PRESS:
+       case GDK_KEY_RELEASE:
+               cerr << "here\n";
+               // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
+               break;
        default:
                warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg;
                break;
index d7e35caa2027414f6bbd944ea8b4d0d13c69f4b2..70c92dfcdd8a74191d10301d406642adf808af55 100644 (file)
@@ -135,7 +135,6 @@ Editor::get_time_line ()
 
        if (free_measure_lines.empty()) {
                line = new ArdourCanvas::SimpleLine (*time_line_group);
-               // cerr << "measure line @ " << line << endl;
                used_measure_lines.push_back (line);
        } else {
                line = free_measure_lines.front();
@@ -182,7 +181,7 @@ Editor::draw_measures ()
                        break;
 
                case TempoMap::Beat:
-                       xpos = p.frame / (gdouble) frames_per_unit;
+                       xpos = frame_to_unit (p.frame);
                        if (last_beat < xpos) {
                                beat_spacing = xpos - last_beat;
                        }
@@ -199,8 +198,8 @@ Editor::draw_measures ()
                        break;
 
                case TempoMap::Beat:
-                       xpos = p.frame / (gdouble) frames_per_unit;
-
+                       xpos = frame_to_unit (p.frame);
+                       
                        if (p.beat == 1) {
                                color = color_map[cMeasureLineBeat];
                        } else {
@@ -214,12 +213,12 @@ Editor::draw_measures ()
                                        break;
                                }
                        }
-
+                       
                        if (cnt == 0 || xpos - last_xpos > 4.0) {
                                line = get_time_line ();
                                line->property_x1() = xpos;
                                line->property_x2() = xpos;
-                               line->property_y2() = canvas_height;
+                               line->property_y2() = 1000;
                                line->property_color_rgba() = color;
                                line->raise_to_top();
                                line->show();
index 4368bf809ffb73a600828b0ed59fe9da3c23f7c0..a696bbfbb1c70bb7bc79334547d133b6bf07f343 100644 (file)
@@ -223,11 +223,9 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev)
        /* XXX optimize this so that it doesn't do it all everytime */
 
        double fraction;
-
        Glib::RefPtr<Gdk::Window> win (meter_metric_area.get_window());
        Glib::RefPtr<Gdk::GC> fg_gc (meter_metric_area.get_style()->get_fg_gc (Gtk::STATE_NORMAL));
        Glib::RefPtr<Gdk::GC> bg_gc (meter_metric_area.get_style()->get_bg_gc (Gtk::STATE_NORMAL));
-       Pango::FontDescription font (meter_metric_area.get_style()->get_font());
        gint x, y, width, height, depth;
        gint pos;
        int  db_points[] = { -50, -10, -3, 0, 6 };
@@ -235,6 +233,8 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev)
        char buf[32];
        GdkRectangle base_rect;
        GdkRectangle draw_rect;
+       int theight;
+       int twidth;
 
        win->get_geometry (x, y, width, height, depth);
        
@@ -246,18 +246,22 @@ GainMeter::meter_metrics_expose (GdkEventExpose *ev)
        gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect);
        win->draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
 
+       Glib::RefPtr<Pango::Layout> layout = meter_metric_area.create_pango_layout("");
+
        for (i = 0; i < sizeof (db_points)/sizeof (db_points[0]); ++i) {
+
                fraction = log_meter (db_points[i]);
                pos = height - (gint) floor (height * fraction);
 
                snprintf (buf, sizeof (buf), "%d", db_points[i]);
 
-               Glib::RefPtr<Pango::Layout> Layout = meter_metric_area.create_pango_layout(buf);
-               // GTK2FIX - how to get twidth, ascent
-               win->draw_layout(fg_gc, width /* - twidth */, pos /*  + ascent */, Layout);
+               layout->set_text (buf);
+               layout->get_pixel_size (twidth, theight);
+
+               win->draw_layout (fg_gc, width - twidth, pos + theight, layout);
        }
 
-       return TRUE;
+       return true;
 }
 
 GainMeter::~GainMeter ()
@@ -281,7 +285,6 @@ GainMeter::update_meters ()
        uint32_t n;
        float peak;
        char buf[32];
-
        
        for (n = 0, i = meters.begin(); i != meters.end(); ++i, ++n) {
                 if ((*i).packed) {
index 7f816a9e6b02b031eb733699114824cd53d2f2f8..0663d7f0346a23e0fdc3fac30ee2a5732b934215 100644 (file)
@@ -43,8 +43,18 @@ class DestructiveFileSource : public FileSource {
        jack_nframes_t write (Sample *src, jack_nframes_t cnt);
 
   private:
-       bool _capture_start;
-       bool _capture_end;
+       static jack_nframes_t xfade_frames;
+       static gain_t* out_coefficient;
+       static gain_t* in_coefficient;
+       static void setup_standard_crossfades (jack_nframes_t sample_rate);
+
+       bool          _capture_start;
+       bool          _capture_end;
+       jack_nframes_t file_pos;
+       Sample*        xfade_buf;
+
+       jack_nframes_t crossfade (Sample* data, jack_nframes_t cnt, int dir);
+
 };
 
 }
index 6145ef9c830a593487e67ca969a391a8853790c9..ce3a103e288e47c9eadc5cac4c25f35ba66b78cd 100644 (file)
@@ -73,7 +73,7 @@ AudioFilter::finish (AudioRegion& region, AudioRegion::SourceList& nsrcs)
        now = localtime (&xnow);
 
        for (AudioRegion::SourceList::iterator si = nsrcs.begin(); si != nsrcs.end(); ++si) {
-               dynamic_cast<FileSource*>((*si))->update_header (session.transport_frame(), *now, xnow);
+               dynamic_cast<FileSource*>((*si))->update_header (region.position(), *now, xnow);
        }
 
        /* create a new region */
index f0813f61dc210322a32a9505679d0badb223b94b..186166e08ce24517bbf3f946d1a3034201b082dd 100644 (file)
@@ -51,6 +51,7 @@ typedef off_t off64_t;
 #endif
 
 #include <errno.h>
+#include <cmath>
 
 #include <pbd/error.h>
 #include <ardour/destructive_filesource.h>
@@ -60,9 +61,19 @@ typedef off_t off64_t;
 using namespace std;
 using namespace ARDOUR;
 
+gain_t* DestructiveFileSource::out_coefficient = 0;
+gain_t* DestructiveFileSource::in_coefficient = 0;
+jack_nframes_t DestructiveFileSource::xfade_frames = 64;
+
 DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate, bool repair_first)
        : FileSource (path, rate, repair_first)
 {
+       if (out_coefficient == 0) {
+               setup_standard_crossfades (rate);
+       }
+
+       xfade_buf = new Sample[xfade_frames];
+
        _capture_start = false;
        _capture_end = false;
 }
@@ -70,17 +81,42 @@ DestructiveFileSource::DestructiveFileSource (string path, jack_nframes_t rate,
 DestructiveFileSource::DestructiveFileSource (const XMLNode& node, jack_nframes_t rate)
        : FileSource (node, rate)
 {
+       if (out_coefficient == 0) {
+               setup_standard_crossfades (rate);
+       }
+
+       xfade_buf = new Sample[xfade_frames];
+
        _capture_start = false;
        _capture_end = false;
 }
 
 DestructiveFileSource::~DestructiveFileSource()
 {
+       delete xfade_buf;
+}
+
+void
+DestructiveFileSource::setup_standard_crossfades (jack_nframes_t rate)
+{
+       xfade_frames = (jack_nframes_t) floor ((/*Config->get_destructive_crossfade_msecs()*/ 64 / 1000.0) * rate);
+
+       out_coefficient = new gain_t[xfade_frames];
+       in_coefficient = new gain_t[xfade_frames];
+
+       for (jack_nframes_t n = 0; n < xfade_frames; ++n) {
+
+               /* XXXX THIS IS NOT THE RIGHT XFADE CURVE: USE A PROPER VOLUMETRIC EQUAL POWER CURVE */
+
+               out_coefficient[n] = n/(gain_t) xfade_frames;
+               in_coefficient[n] = 1.0 - out_coefficient[n];
+       }
 }
 
 int
 DestructiveFileSource::seek (jack_nframes_t frame)
 {
+       file_pos = data_offset + (sizeof (Sample) * frame);
        return 0;
 }
 
@@ -103,6 +139,72 @@ DestructiveFileSource::clear_capture_marks ()
        _capture_end = false;
 }      
 
+jack_nframes_t
+DestructiveFileSource::crossfade (Sample* data, jack_nframes_t cnt, int dir)
+{
+       jack_nframes_t xfade = min (xfade_frames, cnt);
+       jack_nframes_t xfade_bytes = xfade * sizeof (Sample);
+       
+       if (::pread64 (fd, (char *) xfade_buf, xfade_bytes, file_pos) != (off64_t) xfade_bytes) {
+               error << string_compose(_("FileSource: \"%1\" bad read (%2)"), _path, strerror (errno)) << endmsg;
+               return 0;
+       }
+
+       if (xfade == xfade_frames) {
+
+               /* use the standard xfade curve */
+               
+               if (dir) {
+
+                       /* fade new material in */
+
+                       for (jack_nframes_t n = 0; n < xfade; ++n) {
+                               xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]);
+                       }
+               } else {
+
+                       /* fade new material out */
+                       
+                       
+                       for (jack_nframes_t n = 0; n < xfade; ++n) {
+                               xfade_buf[n] = (xfade_buf[n] * in_coefficient[n]) + (data[n] * out_coefficient[n]);
+                       }
+               }
+
+
+       } else {
+
+               /* short xfade, compute custom curve */
+
+               for (jack_nframes_t n = 0; n < xfade; ++n) {
+                       xfade_buf[n] = (xfade_buf[n] * out_coefficient[n]) + (data[n] * in_coefficient[n]);
+               }
+       }
+       
+       if (::pwrite64 (fd, (char *) xfade_buf, xfade, file_pos) != (off64_t) xfade_bytes) {
+               error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+               return 0;
+       }
+
+       /* don't advance file_pos here; if the write fails, we want it left where it was before the overall
+          write, not in the middle of it.
+       */
+       
+       if (xfade < cnt) {
+               jack_nframes_t remaining = (cnt - xfade);
+               int32_t bytes = remaining * sizeof (Sample);
+
+               if (::pwrite64 (fd, (char *) data + remaining, bytes, file_pos) != (off64_t) bytes) {
+                       error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+                       return 0;
+               }
+       }
+
+       file_pos += cnt;
+
+       return cnt;
+}
+
 jack_nframes_t
 DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
 {
@@ -110,17 +212,31 @@ DestructiveFileSource::write (Sample* data, jack_nframes_t cnt)
                LockMonitor lm (_lock, __LINE__, __FILE__);
                
                int32_t byte_cnt = cnt * sizeof (Sample);
-               int32_t byte_pos = data_offset + (_length * sizeof (Sample));
                jack_nframes_t oldlen;
 
-               if (::pwrite64 (fd, (char *) data, byte_cnt, byte_pos) != (off64_t) byte_cnt) {
-                       error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
-                       return 0;
+               if (_capture_start) {
+                       _capture_start = false;
+                       if (crossfade (data, cnt, 1) != cnt) {
+                               return 0;
+                       }
+               } else if (_capture_end) {
+                       _capture_end = false;
+                       if (crossfade (data, cnt, 0) != cnt) {
+                               return 0;
+                       }
+               } else {
+                       if (::pwrite64 (fd, (char *) data, byte_cnt, file_pos) != (off64_t) byte_cnt) {
+                               error << string_compose(_("FileSource: \"%1\" bad write (%2)"), _path, strerror (errno)) << endmsg;
+                               return 0;
+                       }
                }
 
-               oldlen = _length;
-               _length += cnt;
+               oldlen = file_pos;
+               if (file_pos + cnt > _length) {
+                       _length += cnt;
+               }
                _write_data_count = byte_cnt;
+               file_pos += byte_cnt;
 
                if (_build_peakfiles) {
                        PeakBuildRecord *pbr = 0;
index e8c5a54349677a8b26ea51a8cdede969b117ea4c..b8f0068a9174de12fff3ad27e0ac4eb744243852 100644 (file)
@@ -149,7 +149,7 @@ Session::tempoize_region (TimeStretchRequest& tsr)
        xnow = localtime (&now);
 
        for (it = sources.begin(); it != sources.end(); ++it) {
-               dynamic_cast<FileSource*>(*it)->update_header (0, *xnow, now);
+               dynamic_cast<FileSource*>(*it)->update_header (tsr.region->position(), *xnow, now);
        }
 
        region_name = tsr.region->name() + X_(".t");
index ca8d7f725fdf42412f31226d0ec92c56bb7bc58f..efce988c2938237127a0987c3b606474c563c9b1 100644 (file)
@@ -34,6 +34,9 @@ ClickBox::ClickBox (Gtk::Adjustment *adjp, const string &name, bool round_to_ste
 {
        print_func = default_printer;
        print_arg = 0;
+       layout = create_pango_layout ("");
+       twidth = 0;
+       theight = 0;
 
        set_name (name);
        add_events (Gdk::BUTTON_RELEASE_MASK|
@@ -85,6 +88,17 @@ ClickBox::default_printer (char buf[32], Gtk::Adjustment &adj,
 void
 ClickBox::set_label ()
 {
+       if (!print_func) {
+               return;
+       }
+
+       char buf[32];
+
+       print_func (buf, get_adjustment(), print_arg);
+
+       layout->set_text (buf);
+       layout->get_pixel_size (twidth, theight);
+
        queue_draw ();
 }
 
@@ -102,21 +116,27 @@ ClickBox::on_expose_event (GdkEventExpose *ev)
 
        if (print_func) {
 
-               char buf[32];
-
                Glib::RefPtr<Gtk::Style> style (get_style());
-
-               print_func (buf, get_adjustment(), print_arg);
-
-               Glib::RefPtr <Gdk::Window> win (get_window());
-               win->draw_rectangle (style->get_bg_gc(get_state()),
-                                    TRUE, 0, 0, -1, -1);
-
-               {
-                       int width = 0;
-                       int height = 0;
-                       create_pango_layout(buf)->get_pixel_size(width, height);
-                       set_size_request(width, height);
+               Glib::RefPtr<Gdk::GC> fg_gc (style->get_fg_gc (Gtk::STATE_NORMAL));
+               Glib::RefPtr<Gdk::GC> bg_gc (style->get_bg_gc (Gtk::STATE_NORMAL));
+               Glib::RefPtr<Gdk::Window> win (get_window());
+               
+               GdkRectangle base_rect;
+               GdkRectangle draw_rect;
+               gint x, y, width, height, depth;
+               
+               win->get_geometry (x, y, width, height, depth);
+               
+               base_rect.width = width;
+               base_rect.height = height;
+               base_rect.x = 0;
+               base_rect.y = 0;
+               
+               gdk_rectangle_intersect (&ev->area, &base_rect, &draw_rect);
+               win->draw_rectangle (bg_gc, true, draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
+
+               if (twidth && theight) {
+                       win->draw_layout (fg_gc, width - (twidth + 2), (height - theight) + 2, layout);
                }
        }
 
index 4f1ef5ca6b41d1155b3d2e5d3c5933ea3f9b4a0e..c6f2922f3f33b8cefe8bbf5d0479e3cde1c05ed5 100644 (file)
@@ -49,6 +49,10 @@ class ClickBox : public Gtk::DrawingArea, public AutoSpin
        void (*print_func) (char buf[32], Gtk::Adjustment &, void *);
        void *print_arg;
 
+       Glib::RefPtr<Pango::Layout> layout;
+       int twidth;
+       int theight;
+
        void set_label ();
        bool button_press_handler (GdkEventButton *);
        bool button_release_handler (GdkEventButton *);
index a0de774329343a4785be22d7418b30037dc558ab..a7501664f2ffca64934255323a40e91339d6f51d 100644 (file)
@@ -485,10 +485,48 @@ MachineControl::write_track_record_ready (byte *msg, size_t len)
           bit 3: aux track a
           bit 4: aux track b
 
+          the format of the message (its an MMC Masked Write) is:
+          
+          0x41      Command Code
+          <count>   byte count of following data
+          <name>    byte value of the field being written
+          <byte #>  byte number of target byte in the 
+          bitmap being written to
+          <mask>    ones in the mask indicate which bits will be changed
+          <data>    new data for the byte being written
+          
+          by the time this code is executing, msg[0] is the
+          byte number of the target byte. if its zero, we
+          are writing to a special byte in the standard
+          track bitmap, in which the first 5 bits are
+          special. hence the bits for tracks 1 + 2 are bits
+          5 and 6 of the first byte of the track
+          bitmap. so:
+          
+          change track 1:  msg[0] = 0;       << first byte of track bitmap 
+                           msg[1] = 0100000; << binary: bit 5 set
+       
+          change track 2:  msg[0] = 0;       << first byte of track bitmap
+                           msg[1] = 1000000; << binary: bit 6 set
+       
+          change track 3:  msg[0] = 1;       << second byte of track bitmap
+                           msg[1] = 0000001; << binary: bit 0 set
+       
+          the (msg[0] * 7) - 5 computation is an attempt to
+          extract the value of the first track: ie. the one
+          that would be indicated by bit 0 being set.
+               
+           so, if msg[0] = 0, msg[1] = 0100000 (binary),
+          what happens is that base_track = -5, but by the
+          time we check the correct bit, n = 5, and so the
+          computed track for the status change is 0 (first
+          track).
+
+           if msg[0] = 1, then the base track for any change is 2 (the third track), and so on.
        */
 
        /* XXX check needed to make sure we don't go outside the
-          support number of tracks.
+          supported number of tracks.
        */
 
        base_track = (msg[0] * 7) - 5;