/* cdrdao - write audio CD-Rs in disc-at-once mode
*
* Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
*
* This program 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 Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <assert.h>
#include <iostream>
#include <gtkmm.h>
#include <gnome.h>
#include "TocEdit.h"
#include "SampleDisplay.h"
#include "SampleManager.h"
#include "TrackManager.h"
#include "Toc.h"
#include "util.h"
/* XPM data for track marker */
#define TRACK_MARKER_XPM_WIDTH 9
#define TRACK_MARKER_XPM_HEIGHT 12
static gchar *TRACK_MARKER_XPM_DATA[] = {
"9 12 3 1",
" c None",
"X c #000000000000",
". c #FFFFFFFFFFFF",
" ",
" XXXXXXX ",
" XXXXXXX ",
" XXXXXXX ",
" XXXXXXX ",
" XXXXXXX ",
" XXXXXXX ",
" XXXXX ",
" XXX ",
" X ",
" X ",
" X "};
/* XPM data for index marker */
static gchar *INDEX_MARKER_XPM_DATA[] = {
"9 12 3 1",
" c None",
"X c #000000000000",
". c #FFFFFFFFFFFF",
" ",
" XXXXXXX ",
" X.....X ",
" X.....X ",
" X.....X ",
" X.....X ",
" X.....X ",
" X...X ",
" X.X ",
" X ",
" X ",
" X "};
/* XPM data for extend track marker */
static gchar *TRACK_EXTEND_XPM_DATA[] = {
"9 12 3 1",
" c None",
"X c #000000000000",
". c #FFFFFFFFFFFF",
"......XX.",
".....XXX.",
"....XXXX.",
"...XXXXX.",
"..XXXXXX.",
".XXXXXXX.",
"..XXXXXX.",
"...XXXXX.",
"....XXXX.",
".....XXX.",
"......XX.",
"........."};
/* XPM data for extend track marker */
static gchar *INDEX_EXTEND_XPM_DATA[] = {
"9 12 3 1",
" c None",
"X c #000000000000",
". c #FFFFFFFFFFFF",
"......XX.",
".....X.X.",
"....X..X.",
"...X...X.",
"..X....X.",
".X.....X.",
"..X....X.",
"...X...X.",
"....X..X.",
".....X.X.",
"......XX.",
"........."};
SampleDisplay::SampleDisplay():
pixmap_(NULL),
trackMarkerPixmap_(NULL),
indexMarkerPixmap_(NULL),
trackMarkerSelectedPixmap_(NULL),
indexMarkerSelectedPixmap_(NULL),
trackExtendPixmap_(NULL),
indexExtendPixmap_(NULL),
drawGc_(NULL)
{
adjustment_ = new Gtk::Adjustment(0.0, 0.0, 1.0);
adjustment_->signal_value_changed().connect(mem_fun(*this,
&SampleDisplay::scrollTo));
trackManager_ = NULL;
width_ = height_ = chanHeight_ = lcenter_ = rcenter_ = 0;
timeLineHeight_ = timeLineY_ = 0;
timeTickWidth_ = 0;
timeTickSep_ = 20;
sampleStartX_ = sampleEndX_ = sampleWidthX_ = 0;
minSample_ = maxSample_ = resolution_ = 0;
tocEdit_ = NULL;
chanSep_ = 10;
cursorControlExtern_ = false;
cursorDrawn_ = false;
cursorX_ = 0;
markerSet_ = false;
selectionSet_ = false;
regionSet_ = false;
dragMode_ = DRAG_NONE;
pickedTrackMarker_ = NULL;
selectedTrack_ = 0;
selectedIndex_ = 0;
signal_expose_event().connect(mem_fun(*this,
&SampleDisplay::handleExposeEvent));
signal_configure_event().
connect(mem_fun(*this, &SampleDisplay::handleConfigureEvent));
signal_motion_notify_event().
connect(mem_fun(*this, &SampleDisplay::handleMotionNotifyEvent));
signal_button_press_event().
connect(mem_fun(*this, &SampleDisplay::handleButtonPressEvent));
signal_button_release_event().
connect(mem_fun(*this, &SampleDisplay::handleButtonReleaseEvent));
signal_enter_notify_event().
connect(mem_fun(*this, &SampleDisplay::handleEnterEvent));
signal_leave_notify_event().
connect(mem_fun(*this, &SampleDisplay::handleLeaveEvent));
set_events(Gdk::EXPOSURE_MASK
| Gdk::LEAVE_NOTIFY_MASK
| Gdk::ENTER_NOTIFY_MASK
| Gdk::BUTTON_PRESS_MASK
| Gdk::BUTTON_RELEASE_MASK
| Gdk::POINTER_MOTION_MASK
| Gdk::POINTER_MOTION_HINT_MASK);
}
void SampleDisplay::setTocEdit(TocEdit *t)
{
tocEdit_ = t;
Toc *toc = tocEdit_->toc();
markerSet_ = false;
selectionSet_ = false;
regionSet_ = false;
minSample_ = 0;
if (toc->length().samples() > 0) {
maxSample_ = toc->length().samples() - 1;
}
else {
maxSample_ = 0;
}
}
void SampleDisplay::updateToc(unsigned long smin, unsigned long smax)
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
if (smin <= smax) {
minSample_ = smin;
maxSample_ = smax;
}
if (toc->length().samples() == 0) {
minSample_ = maxSample_ = 0;
}
else {
if (maxSample_ >= toc->length().samples()) {
// adjust 'maxSample_' to reduced length
unsigned long len = maxSample_ - minSample_;
maxSample_ = toc->length().samples() - 1;
if (maxSample_ > len) {
minSample_ = maxSample_ - len;
}
else {
minSample_ = 0;
}
}
}
setView(minSample_, maxSample_);
}
void SampleDisplay::setView(unsigned long start, unsigned long end)
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
if (end < start)
end = start;
unsigned long len = end - start + 1;
if (len < 3 && toc != NULL) {
end = start + 2;
if (end >= toc->length().samples()) {
if (toc->length().samples() != 0)
end = toc->length().samples() - 1;
else
end = 0;
if (end <= 2)
start = 0;
else
start = end - 2;
}
len = (end == 0 ? 0 : 3);
}
minSample_ = start;
maxSample_ = end;
updateSamples();
redraw(0, 0, width_, height_, 0);
GtkAdjustment *adjust = adjustment_->gobj();
if (toc == NULL) {
adjust->lower = 0.0;
adjust->upper = 1.0;
adjust->value = 0.0;
adjust->page_size = 0.0;
}
else {
adjust->lower = 0.0;
adjust->upper = toc->length().samples();
adjust->value = minSample_;
adjust->step_increment = len / 4;
if (adjust->step_increment == 0.0)
adjust->step_increment = 1.0;
adjust->page_increment = len / 1.1;
adjust->page_size = len;
}
adjustment_->changed();
}
void SampleDisplay::getView(unsigned long *start, unsigned long *end)
{
*start = minSample_;
*end = maxSample_;
}
bool SampleDisplay::getSelection(unsigned long *start, unsigned long *end)
{
if (selectionSet_) {
*start = selectionStartSample_;
*end = selectionEndSample_;
return true;
}
return false;
}
int SampleDisplay::getMarker(unsigned long *sample)
{
if (markerSet_) {
*sample = markerSample_;
return 1;
}
return 0;
}
void SampleDisplay::setSelectedTrackMarker(int trackNr, int indexNr)
{
selectedTrack_ = trackNr;
selectedIndex_ = indexNr;
}
void SampleDisplay::setRegion(unsigned long start, unsigned long end)
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
if (end <= start || end >= toc->length().samples()) {
regionSet_ = false;
}
else {
regionStartSample_ = start;
regionEndSample_ = end;
regionSet_ = true;
}
setView(minSample_, maxSample_);
}
void SampleDisplay::clearRegion()
{
bool wasSet = regionSet_;
regionSet_ = false;
if (wasSet) {
setView(minSample_, maxSample_);
}
}
int SampleDisplay::getRegion(unsigned long *start, unsigned long *end)
{
if (regionSet_) {
*start = regionStartSample_;
*end = regionEndSample_;
return 1;
}
return 0;
}
void SampleDisplay::setCursor(int ctrl, unsigned long sample)
{
if (ctrl == 0) {
cursorControlExtern_ = false;
}
else {
cursorControlExtern_ = true;
gint x = sample2pixel(sample);
if (x >= 0)
drawCursor(x);
else
undrawCursor();
}
}
void SampleDisplay::getColor(const char *colorName, Gdk::Color *color)
{
if (!color->parse(colorName) || !get_colormap()->alloc_color(*color)) {
message(-1, _("Cannot allocate color \"%s\""), colorName);
*color = get_style()->get_black();
}
}
void SampleDisplay::scrollTo()
{
unsigned long minSample, maxSample;
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
GtkAdjustment *adjust = adjustment_->gobj();
if (adjust->page_size == 0.0)
return;
minSample = (unsigned long)adjust->value;
maxSample = (unsigned long)(adjust->value + adjust->page_size) - 1;
if (maxSample >= toc->length().samples()) {
maxSample = toc->length().samples() - 1;
if (maxSample <= (unsigned long)(adjust->page_size - 1))
minSample = 0;
else
minSample = maxSample - (unsigned long)(adjust->page_size - 1);
}
viewModified(minSample, maxSample);
}
unsigned long SampleDisplay::pixel2sample(gint x)
{
if (tocEdit_ == NULL)
return 0;
Toc *toc = tocEdit_->toc();
unsigned long sample;
if (toc->length().lba() == 0)
return 0;
assert(x >= sampleStartX_ && x <= sampleEndX_);
x -= sampleStartX_;
double res = maxSample_ - minSample_;
res /= sampleWidthX_ - 1;
sample = (unsigned long)(minSample_ + res * x + 0.5);
unsigned long round = 75 * 588; // 1 second
unsigned long rest;
if (res >= 2 * round) {
if ((rest = sample % round) != 0)
sample += round - rest;
}
else {
round = 588; // 1 block
if (res >= 2 * round) {
if ((rest = sample % round) != 0)
sample += round - rest;
}
}
if (sample > maxSample_)
sample = maxSample_;
return sample;
}
gint SampleDisplay::sample2pixel(unsigned long sample)
{
if (sample < minSample_ || sample > maxSample_)
return -1;
unsigned long len = maxSample_ - minSample_;
double val = sample - minSample_;
val *= sampleWidthX_ - 1;
val /= len;
return (gint)(sampleStartX_ + val + 0.5);
}
bool SampleDisplay::handleConfigureEvent(GdkEventConfigure *event)
{
Glib::RefPtr<Pango::Context> context = get_pango_context();
Pango::FontMetrics metrics = context->get_metrics(get_style()->get_font());
if (!drawGc_) {
Glib::RefPtr<Gdk::Bitmap> mask;
// mask = Gdk::Bitmap::create(NULL, get_width(), get_height());
Glib::RefPtr<const Gdk::Drawable> window(get_window());
drawGc_ = Gdk::GC::create(get_window());
getColor("darkslateblue", &sampleColor_);
getColor("red3", &middleLineColor_);
getColor("gold2", &cursorColor_);
getColor("red", &markerColor_);
getColor("#ffc0e0", &selectionBackgroundColor_);
timeLineHeight_ = ((metrics.get_ascent() + metrics.get_descent())
/ Pango::SCALE);
trackLineHeight_ = ((metrics.get_ascent() + metrics.get_descent())
/ Pango::SCALE);
trackMarkerPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
get_style()->get_white(),
TRACK_MARKER_XPM_DATA);
indexMarkerPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
get_style()->get_white(),
INDEX_MARKER_XPM_DATA);
trackMarkerSelectedPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
markerColor_,
TRACK_MARKER_XPM_DATA);
indexMarkerSelectedPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
markerColor_,
INDEX_MARKER_XPM_DATA);
trackExtendPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
get_style()->get_white(),
TRACK_EXTEND_XPM_DATA);
indexExtendPixmap_ =
Gdk::Pixmap::create_from_xpm(window, mask,
get_style()->get_white(),
INDEX_EXTEND_XPM_DATA);
trackMarkerWidth_ = ((metrics.get_approximate_digit_width() /
Pango::SCALE) * 5) + TRACK_MARKER_XPM_WIDTH + 2;
trackManager_ = new TrackManager(TRACK_MARKER_XPM_WIDTH);
}
width_ = get_width();
height_ = get_height();
// Don't even try to do anything smart if we haven't received a
// reasonable window size yet. This will keep pixmap_ to NULL. This
// is important because during startup we don't control how the
// configure_event are timed wrt to gcdmaster bringup.
if (width_ <= 1 || height_ <= 1)
return true;
chanHeight_ = (height_ - timeLineHeight_ - trackLineHeight_ - 2) / 2;
lcenter_ = chanHeight_ / 2 + trackLineHeight_;
rcenter_ = lcenter_ + timeLineHeight_ + chanHeight_;
trackLineY_ = trackLineHeight_ - 1;
timeLineY_ = chanHeight_ + timeLineHeight_ + trackLineHeight_;
timeTickWidth_ = ((metrics.get_approximate_digit_width() /
Pango::SCALE) * 13) + 3;
sampleStartX_ = 10;
sampleEndX_ = width_ - 10;
sampleWidthX_ = sampleEndX_ - sampleStartX_ + 1;
pixmap_ = Gdk::Pixmap::create(get_window(), get_width(), get_height(), -1);
if (width_ > 100 && height_ > 100)
updateSamples();
return true;
}
bool SampleDisplay::handleExposeEvent (GdkEventExpose *event)
{
redraw(event->area.x, event->area.y, event->area.width, event->area.height,
0);
return false;
}
bool SampleDisplay::handleButtonPressEvent(GdkEventButton *event)
{
gint x = (gint)event->x;
gint y = (gint)event->y;
dragMode_ = DRAG_NONE;
// e.g. if audio is playing
if (cursorControlExtern_)
return true;
if (event->button == 1 && x >= sampleStartX_ && x <= sampleEndX_) {
if (y > trackLineY_) {
dragMode_ = DRAG_SAMPLE_MARKER;
dragStart_ = dragEnd_ = x;
}
else {
if ((pickedTrackMarker_ = trackManager_->pick(x - sampleStartX_ + 4,
&dragStopMin_,
&dragStopMax_)) != NULL) {
dragMode_ = DRAG_TRACK_MARKER;
dragStart_ = dragEnd_ = x;
dragLastX_ = -1;
dragStopMin_ += sampleStartX_;
dragStopMax_ += sampleStartX_;
}
}
}
return true;
}
bool SampleDisplay::handleButtonReleaseEvent(GdkEventButton *event)
{
gint x = (gint)event->x;
if (cursorControlExtern_)
return false;
if (x < sampleStartX_) {
x = sampleStartX_;
}
else if (x > sampleEndX_) {
x = sampleEndX_;
}
if (event->button == 1 && dragMode_ != DRAG_NONE) {
if (dragMode_ == DRAG_SAMPLE_MARKER) {
if (dragStart_ - x >= -5 && dragStart_ - x <= 5) {
selectionSet_ = false;
selectionCleared();
markerSet(pixel2sample(dragStart_));
}
else {
selectionSet_ = true;
if (x > dragStart_) {
selectionStartSample_ = pixel2sample(dragStart_);
selectionEndSample_ = pixel2sample(x);
selectionStart_ = dragStart_;
selectionEnd_ = x;
}
else {
selectionEndSample_ = pixel2sample(dragStart_);
selectionStartSample_ = pixel2sample(x);
selectionEnd_ = dragStart_;
selectionStart_ = x;
}
selectionSet(selectionStartSample_, selectionEndSample_);
}
}
else if (dragMode_ == DRAG_TRACK_MARKER) {
if (dragStart_ - x >= -5 && dragStart_ - x <= 5) {
trackManager_->select(pickedTrackMarker_);
selectedTrack_ = pickedTrackMarker_->trackNr;
selectedIndex_ = pickedTrackMarker_->indexNr;
drawTrackLine();
trackMarkSelected(pickedTrackMarker_->track, selectedTrack_,
selectedIndex_);
}
else {
selectedTrack_ = pickedTrackMarker_->trackNr;
selectedIndex_ = pickedTrackMarker_->indexNr;
trackMarkMoved(pickedTrackMarker_->track, selectedTrack_,
selectedIndex_, pixel2sample(x));
}
pickedTrackMarker_ = NULL;
}
dragMode_ = DRAG_NONE;
drawCursor(x);
redraw(0, 0, width_, height_, 0);
}
return true;
}
bool SampleDisplay::handleMotionNotifyEvent (GdkEventMotion *event)
{
gint x, y;
GdkModifierType state;
if (cursorControlExtern_)
return TRUE;
if (event->is_hint)
gdk_window_get_pointer (event->window, &x, &y, &state);
else {
x = (gint)event->x;
y = (gint)event->y;
state = (GdkModifierType) event->state;
}
if (dragMode_ == DRAG_SAMPLE_MARKER) {
gint dw = 0;
gint dx = 0;
if (x < sampleStartX_)
x = sampleStartX_;
else if (x > sampleEndX_)
x = sampleEndX_;
if (selectionEnd_ > dragStart_) {
if (x < selectionEnd_) {
redraw(x + 1, 0, selectionEnd_ - x, height_, 0x01);
if (x < dragStart_) {
dw = dragStart_ - x + 1;
dx = x;
}
}
else {
dw = x - selectionEnd_;
dx = selectionEnd_ + 1;
}
}
else if (selectionEnd_ < dragStart_) {
if (x > selectionEnd_) {
redraw(selectionEnd_, 0, x - selectionEnd_, height_, 0x01);
if (x > dragStart_) {
dw = x - dragStart_ + 1;
dx = dragStart_;
}
}
else {
dw = selectionEnd_ - x;
dx = x;
}
}
if (dw != 0) {
drawGc_->set_foreground(cursorColor_);
drawGc_->set_function(Gdk::XOR);
get_window()->draw_rectangle(drawGc_, TRUE, dx, 0, dw, height_ - 1);
drawGc_->set_function(Gdk::COPY);
}
selectionEnd_ = x;
}
else if (dragMode_ == DRAG_TRACK_MARKER) {
if (x < dragStopMin_)
x = dragStopMin_;
if (x > dragStopMax_)
x = dragStopMax_;
if (dragLastX_ > 0) {
drawTrackMarker(2, dragLastX_, 0, 0, 0, 0);
}
drawTrackMarker(1, x, pickedTrackMarker_->trackNr,
pickedTrackMarker_->indexNr, 0, 0);
dragLastX_ = x;
drawCursor(x);
}
else {
drawCursor(x);
}
return TRUE;
}
bool SampleDisplay::handleEnterEvent(GdkEventCrossing *event)
{
if (cursorControlExtern_)
return true;
drawCursor((gint)event->x);
return true;
}
bool SampleDisplay::handleLeaveEvent(GdkEventCrossing *event)
{
if (cursorControlExtern_)
return true;
undrawCursor();
return true;
}
// drawMask: 0x01: do not draw cursor
// 0x02: do not draw marker
void SampleDisplay::redraw(gint x, gint y, gint width, gint height,
int drawMask)
{
if (pixmap_ == 0)
return;
get_window()->draw_drawable(drawGc_, pixmap_, x, y, x, y, width, height);
if ((drawMask & 0x02) == 0)
drawMarker();
if ((drawMask & 0x01) == 0 && cursorDrawn_) {
cursorDrawn_ = false;
drawCursor(cursorX_);
}
}
void SampleDisplay::drawMarker()
{
if (markerSet_) {
drawGc_->set_foreground(markerColor_);
markerX_ = sample2pixel(markerSample_);
if (markerX_ >= 0)
get_window()->draw_line(drawGc_, markerX_, trackLineY_,
markerX_, height_ - 1);
}
}
void SampleDisplay::setMarker(unsigned long sample)
{
if (markerSet_)
redraw(markerX_, 0, 1, height_, 0x02);
markerSample_ = sample;
markerSet_ = true;
drawMarker();
}
void SampleDisplay::clearMarker()
{
if (markerSet_)
redraw(markerX_, 0, 1, height_, 0x02);
markerSet_ = false;
}
void SampleDisplay::updateSamples()
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
if (pixmap_ == 0)
return;
gint halfHeight = chanHeight_ / 2;
drawGc_->set_foreground(get_style()->get_white());
pixmap_->draw_rectangle(drawGc_, TRUE, 0, 0, width_, height_);
long res = (maxSample_ - minSample_ + 1)/sampleWidthX_;
long bres = res / tocEdit_->sampleManager()->blocking();
gint i;
double pos;
long j;
unsigned long s;
short lnegsum, lpossum, rnegsum, rpossum;
gint regionStart = -1;
gint regionEnd = -1;
int regionActive = 0;
if (regionSet_) {
if (regionStartSample_ <= maxSample_ &&
regionEndSample_ >= minSample_) {
if (regionStartSample_ > minSample_)
regionStart = sample2pixel(regionStartSample_);
else
regionStart = sampleStartX_;
if (regionEndSample_ < maxSample_)
regionEnd = sample2pixel(regionEndSample_);
else
regionEnd = sampleEndX_;
}
if (regionStart >= 0 && regionEnd >= regionStart) {
drawGc_->set_foreground(selectionBackgroundColor_);
pixmap_->draw_rectangle(drawGc_, TRUE,
regionStart, lcenter_ - halfHeight,
regionEnd - regionStart + 1, chanHeight_);
pixmap_->draw_rectangle(drawGc_, TRUE,
regionStart, rcenter_ - halfHeight,
regionEnd - regionStart + 1, chanHeight_);
}
}
drawGc_->set_foreground(sampleColor_);
if (bres > 0) {
for (s = minSample_, i = sampleStartX_;
s < maxSample_ && i <= sampleEndX_;
s += res, i++) {
lnegsum = lpossum = rnegsum = rpossum = 0;
if (regionStart != -1 && i >= regionStart && regionActive == 0) {
regionActive = 1;
drawGc_->set_foreground(markerColor_);
}
else if (regionActive == 1 && i > regionEnd) {
regionActive = 2;
drawGc_->set_foreground(sampleColor_);
}
tocEdit_->sampleManager()->getPeak(s, s + res, &lnegsum, &lpossum,
&rnegsum, &rpossum);
pos = double(lnegsum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
pos = double(lpossum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
pos = double(rnegsum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
pos = double(rpossum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
}
}
else if (maxSample_ > 0 && res >= 1) {
TocReader reader(toc);
if (reader.openData() == 0) {
Sample *sampleBuf = new Sample[tocEdit_->sampleManager()->blocking()];
double dres = double(maxSample_ - minSample_ + 1)/double(sampleWidthX_);
double ds;
for (ds = minSample_, i = sampleStartX_;
ds < maxSample_ && i <= sampleEndX_;
ds += dres, i++) {
lnegsum = lpossum = rnegsum = rpossum = 0;
if (reader.seekSample((long)ds) == 0 &&
reader.readSamples(sampleBuf, res) == res) {
for (j = 0; j < res; j++) {
if (sampleBuf[j].left() < lnegsum)
lnegsum = sampleBuf[j].left();
if (sampleBuf[j].left() > lpossum)
lpossum = sampleBuf[j].left();
if (sampleBuf[j].right() < rnegsum)
rnegsum = sampleBuf[j].right();
if (sampleBuf[j].right() > rpossum)
rpossum = sampleBuf[j].right();
}
}
if (regionStart != -1 && i >= regionStart && regionActive == 0) {
regionActive = 1;
drawGc_->set_foreground(markerColor_);
}
else if (regionActive == 1 && i > regionEnd) {
regionActive = 2;
drawGc_->set_foreground(sampleColor_);
}
pos = double(lnegsum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
pos = double(lpossum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, lcenter_, i, lcenter_ - (gint)pos);
pos = double(rnegsum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
pos = double(rpossum) * halfHeight;
pos /= SHRT_MAX;
if (pos != 0)
pixmap_->draw_line(drawGc_, i, rcenter_, i, rcenter_ - (gint)pos);
}
delete[] sampleBuf;
reader.closeData();
}
}
else if (toc != NULL && maxSample_ > minSample_ + 1) {
TocReader reader(toc);
if (reader.openData() == 0) {
long len = maxSample_ - minSample_ + 1;
Sample *sampleBuf = new Sample[len];
double pres = double(sampleWidthX_ - 1) / double(len - 1);
double di;
gint pos1;
gint lastPosLeft, lastPosRight;
if (reader.seekSample(minSample_) == 0 &&
reader.readSamples(sampleBuf, len) == len) {
for (j = 1, di = sampleStartX_ + pres;
j < len && di < sampleEndX_ + 1; j++, di += pres) {
if (regionStart != -1 && regionActive == 0 &&
minSample_ + j - 1 >= regionStartSample_ &&
minSample_ + j <= regionEndSample_) {
regionActive = 1;
drawGc_->set_foreground(markerColor_);
}
else if (regionActive == 1 && minSample_ + j > regionEndSample_) {
regionActive = 2;
drawGc_->set_foreground(sampleColor_);
}
pos = sampleBuf[j - 1].left() * halfHeight;
pos /= SHRT_MAX;
pos1 = sampleBuf[j].left() * halfHeight;
pos1 /= SHRT_MAX;
lastPosLeft = pos1;
if (pos != 0 || pos1 != 0)
pixmap_->draw_line(drawGc_, long(di - pres), lcenter_ - (gint)pos,
long(di), lcenter_ - pos1);
pos = sampleBuf[j - 1].right() * halfHeight;
pos /= SHRT_MAX;
pos1 = sampleBuf[j].right() * halfHeight;
pos1 /= SHRT_MAX;
lastPosRight = pos1;
if (pos != 0 || pos1 != 0)
pixmap_->draw_line(drawGc_, long(di - pres), rcenter_ - (gint)pos,
long(di), rcenter_ - pos1);
}
if (&pixmap_ == 0)
std::cout << "null !!" << std::endl;
if (0 && (gint)di < sampleEndX_) {
pos = sampleBuf[len -1].left() * halfHeight;
pos /= SHRT_MAX;
if (pos != 0 || lastPosLeft != 0)
pixmap_->draw_line(drawGc_, long(di), lcenter_ - lastPosLeft,
sampleEndX_, lcenter_ - (gint)pos);
pos = sampleBuf[len - 1].right() * halfHeight;
pos /= SHRT_MAX;
if (pos != 0 || lastPosRight != 0)
pixmap_->draw_line(drawGc_, long(di), rcenter_ - lastPosRight,
sampleEndX_, rcenter_ - (gint)pos);
}
}
delete[] sampleBuf;
}
}
drawGc_->set_foreground(middleLineColor_);
pixmap_->draw_line(drawGc_, sampleStartX_, lcenter_, sampleEndX_, lcenter_);
pixmap_->draw_line(drawGc_, sampleStartX_, rcenter_, sampleEndX_, rcenter_);
drawGc_->set_foreground(get_style()->get_black());
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ - halfHeight,
sampleEndX_ + 1, lcenter_ - halfHeight);
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ + halfHeight,
sampleEndX_ + 1, lcenter_ + halfHeight);
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, lcenter_ - halfHeight,
sampleStartX_ - 1, lcenter_ + halfHeight);
pixmap_->draw_line(drawGc_, sampleEndX_ + 1, lcenter_ - halfHeight,
sampleEndX_ + 1, lcenter_ + halfHeight);
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ - halfHeight,
sampleEndX_ + 1, rcenter_ - halfHeight);
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ + halfHeight,
sampleEndX_ + 1, rcenter_ + halfHeight);
pixmap_->draw_line(drawGc_, sampleStartX_ - 1, rcenter_ + halfHeight,
sampleStartX_ - 1, rcenter_ - halfHeight);
pixmap_->draw_line(drawGc_, sampleEndX_ + 1, rcenter_ + halfHeight,
sampleEndX_ + 1, rcenter_ - halfHeight);
drawTimeLine();
trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_);
if (selectedTrack_ > 0) {
trackManager_->select(selectedTrack_, selectedIndex_);
}
drawTrackLine();
}
void SampleDisplay::drawCursor(gint x)
{
if (pixmap_ == 0)
return;
if (x < sampleStartX_ || x > sampleEndX_)
return;
if (cursorDrawn_ && cursorX_ != x) {
redraw(cursorX_, 0, 1, height_, 0x01);
}
if (!cursorDrawn_ || cursorX_ != x) {
drawGc_->set_foreground(cursorColor_);
get_window()->draw_line(drawGc_, x, trackLineY_, x, height_ - 1);
}
cursorDrawn_ = true;
cursorX_ = x;
if (cursorControlExtern_ == false)
cursorMoved(pixel2sample(x));
}
void SampleDisplay::undrawCursor()
{
if (cursorDrawn_) {
redraw(cursorX_, 0, 1, height_, 0x01);
cursorDrawn_ = false;
}
}
void SampleDisplay::drawTimeTick(gint x, gint y, unsigned long sample)
{
char buf[50];
if (pixmap_ == 0)
return;
unsigned long min = sample / (60 * 44100);
sample %= 60 * 44100;
unsigned long sec = sample / 44100;
sample %= 44100;
unsigned long frame = sample / 588;
sample %= 588;
sprintf(buf, "%lu:%02lu:%02lu.%03lu", min, sec, frame, sample);
drawGc_->set_foreground(get_style()->get_black());
pixmap_->draw_line(drawGc_, x, y - timeLineHeight_, x, y);
Glib::RefPtr<Pango::Layout> playout =
Pango::Layout::create(get_pango_context());
playout->set_text(buf);
pixmap_->draw_layout(drawGc_, x + 3, y - timeLineHeight_ + 1, playout);
}
void SampleDisplay::drawTimeLine()
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
if (toc->length().lba() == 0)
return;
gint sep = timeTickWidth_ + timeTickSep_;
unsigned long maxNofTicks = (sampleWidthX_ + timeTickSep_) / sep;
gint x;
unsigned long len = maxSample_ - minSample_ + 1;
unsigned long dt;
unsigned long dtx;
unsigned long startSample;
unsigned long s;
if ((s = len / (60 * 44100)) > 1) {
dt = 60 * 44100;
}
else if ((s = len / 44100) > 1) {
dt = 44100;
}
else if ((s = len / 588) > 1) {
dt = 588;
}
else {
dt = 1;
s = len;
}
if (s > maxNofTicks) {
dtx = s / maxNofTicks;
if (s % maxNofTicks != 0)
dtx++;
dtx *= dt;
}
else {
dtx = dt;
}
if (dt > 1) {
if (minSample_ % dt == 0) {
startSample = minSample_;
}
else {
startSample = minSample_ / dt;
startSample = startSample * dt + dt;
}
}
else {
startSample = minSample_;
}
for (s = startSample; s < maxSample_; s += dtx) {
x = sample2pixel(s);
if (x + timeTickWidth_ <= sampleEndX_)
drawTimeTick(x, timeLineY_, s);
}
}
// Draws track marker.
// mode: 0: draw on 'pixmap_'
// 1: draw on window
// 2: redraw region at given position
void SampleDisplay::drawTrackMarker(int mode, gint x, int trackNr,
int indexNr, int selected, int extend)
{
if (mode < 2) {
char buf[20];
sprintf(buf, "%d.%d", trackNr, indexNr);
Glib::RefPtr<Gdk::Pixmap> marker;
if (extend) {
marker = (indexNr == 1 ? trackExtendPixmap_ : indexExtendPixmap_);
}
else {
if (selected)
marker = (indexNr == 1 ? trackMarkerSelectedPixmap_ :
indexMarkerSelectedPixmap_);
else
marker = (indexNr == 1 ? trackMarkerPixmap_ : indexMarkerPixmap_);
}
Glib::RefPtr<Gdk::Window> win = get_window();
Glib::RefPtr<Gdk::Drawable> dr = win;
if (mode == 0)
dr = pixmap_;
if (mode == 0) {
if (selected)
drawGc_->set_foreground(markerColor_);
else
drawGc_->set_foreground(get_style()->get_white());
dr->draw_rectangle(drawGc_, TRUE, x-4, trackLineY_ - trackLineHeight_,
trackMarkerWidth_, trackLineHeight_);
}
drawGc_->set_foreground(get_style()->get_black());
dr->draw_drawable(drawGc_, marker, 0, 0,
x - 4, trackLineY_ - TRACK_MARKER_XPM_HEIGHT,
TRACK_MARKER_XPM_WIDTH, TRACK_MARKER_XPM_HEIGHT);
Glib::RefPtr<Pango::Layout> playout =
Pango::Layout::create(get_pango_context());
playout->set_text(buf);
dr->draw_layout(drawGc_,
x + TRACK_MARKER_XPM_WIDTH / 2 + 2,
trackLineY_ - trackLineHeight_ + 2,
playout);
}
else {
redraw(x - 4, trackLineY_ - trackLineHeight_, trackMarkerWidth_,
trackLineHeight_, 0x03);
}
}
void SampleDisplay::drawTrackLine()
{
const TrackManager::Entry *run;
const TrackManager::Entry *selected = NULL;
for (run = trackManager_->first(); run != NULL;
run = trackManager_->next()) {
if (run->selected != 0 && run->extend == 0) {
selected = run;
}
else if (run->indexNr != 1 || run->extend != 0) {
drawTrackMarker(0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr,
0, run->extend);
}
}
for (run = trackManager_->first(); run != NULL;
run = trackManager_->next()) {
if (run->indexNr == 1 && run->selected == 0 && run->extend == 0) {
drawTrackMarker(0, sampleStartX_ + run->xpos, run->trackNr, run->indexNr,
0, run->extend);
}
}
if (selected != NULL)
drawTrackMarker(0, sampleStartX_ + selected->xpos, selected->trackNr,
selected->indexNr, 1, 0);
}
void SampleDisplay::updateTrackMarks()
{
if (tocEdit_ == NULL)
return;
Toc *toc = tocEdit_->toc();
drawGc_->set_foreground(get_style()->get_white());
pixmap_->draw_rectangle(drawGc_, TRUE,
sampleStartX_ - 4, trackLineY_ - trackLineHeight_,
width_ - sampleStartX_, trackLineHeight_);
trackManager_->update(toc, minSample_, maxSample_, sampleWidthX_);
if (selectedTrack_ > 0) {
trackManager_->select(selectedTrack_, selectedIndex_);
}
drawTrackLine();
redraw(0, 0, width_, height_, 0x03);
}
syntax highlighted by Code2HTML, v. 0.9.1