pkg://gkrellmss_2.6.orig.tar.gz:31522/
gkrellmss-2.6.orig/
src/oscope.c
downloads
/* GKrellMSS - GKrellM Sound Scope
| Copyright (C) 2002-2004 Bill Wilson
|
| Author: Bill Wilson bill@gkrellm.net
|
| This program is free software which I release under the GNU General Public
| License. You may redistribute and/or modify this program under the terms
| of that 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.
|
| To get a copy of the GNU General Puplic License, write to the Free Software
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "gkrellmss.h"
static Oscope *oscope;
static void
trigger_delay(gint channel)
{
SoundSample *ss = gkrellmss->buffer;
gfloat flimit;
gint y0, i, n, limit, trigger, delay;
trigger = (gint) (oscope->vert_trigger * oscope->vert_max);
delay = -2;
flimit = oscope->samples_per_point;
limit = flimit;
for (i = 0; i < gkrellmss->buf_count - limit; )
{
for (y0 = 0, n = 0; n < limit; ++n)
{
if (channel == CHANNEL_L)
y0 += ss[i].left;
else if (channel == CHANNEL_R)
y0 += ss[i].right;
else if (channel == CHANNEL_LR)
y0 += (ss[i].left + ss[i].right) / 2;
}
y0 = y0 / limit;
if (y0 < trigger)
delay = -1;
if (y0 >= trigger && delay == -1)
{
delay = i;
break;
}
flimit += oscope->samples_per_point;
i = flimit;
}
gkrellmss->buf_index = (delay < 0) ? 0 : delay;
}
static void
draw_oscope_line_trace(gint channel)
{
GkrellmChart *chart = gkrellmss->chart;
SoundSample *ss = gkrellmss->buffer;
gfloat flimit;
gint x, x0, y0, y1, i, limit, n;
gdk_gc_set_foreground(gkrellmss->gc, gkrellm_in_color());
y1 = oscope->y_append;
x0 = oscope->x_append;
oscope->x_append = 0;
oscope->y_append = 0;
flimit = gkrellmss->buf_index + oscope->samples_per_point;
for (i = gkrellmss->buf_index, x = x0; x < chart->w;
x += oscope->dx_per_point)
{
limit = flimit;
if (limit >= gkrellmss->buf_count - 1)
{
oscope->y_append = y1;
oscope->x_append = x;
break;
}
for (n = 0, y0 = 0; i < limit; ++i, ++n)
{
if (channel == CHANNEL_L)
y0 += ss[i].left;
else if (channel == CHANNEL_R)
y0 += ss[i].right;
else if (channel == CHANNEL_LR)
y0 += (ss[i].left + ss[i].right) / 2;
}
y0 /= n;
y0 = (chart->h / 2) * -y0 / oscope->vert_max;
y0 += chart->h / 2;
if (x > 0)
{
gdk_draw_line(chart->pixmap, gkrellmss->gc,
x - oscope->dx_per_point, y1, x, y0);
}
y1 = y0;
flimit += oscope->samples_per_point;
}
gkrellmss->buf_index = 0;
gkrellmss->buf_count = 0;
}
static void
draw_oscope_bar_trace(gint channel)
{
GkrellmChart *chart = gkrellmss->chart;
SoundSample *ss = gkrellmss->buffer;
gfloat flimit;
gint x, x0, y, y0, y1, i, limit, n;
gint y0_prev, y1_prev;
gdk_gc_set_foreground(gkrellmss->gc, gkrellm_in_color());
y = y0 = y1 = 0;
y0_prev = y1_prev = oscope->y_append;
x0 = oscope->x_append;
oscope->x_append = 0;
oscope->y_append = 0;
flimit = gkrellmss->buf_index + oscope->samples_per_point;
for (i = gkrellmss->buf_index, x = x0; x < chart->w;
x += oscope->dx_per_point)
{
limit = flimit;
if (limit >= gkrellmss->buf_count - 1)
{
oscope->y_append = (y1_prev + y0_prev) / 2;
oscope->x_append = x;
break;
}
for (n = 0; i < limit; ++i, ++n)
{
if (channel == CHANNEL_L)
y = ss[i].left;
else if (channel == CHANNEL_R)
y = ss[i].right;
else if (channel == CHANNEL_LR)
y = (ss[i].left + ss[i].right) / 2;
else
break;
if (n == 0)
y0 = y1 = y;
else
{
if (y < y0)
y0 = y;
if (y > y1)
y1 = y;
}
if (x > 0)
{
if (y0 > y1_prev)
y0 = y1_prev;
if (y1 < y0_prev)
y1 = y0_prev;
}
}
y0_prev = y0;
y1_prev = y1;
y0 = (chart->h / 2) * -y0 / oscope->vert_max;
y1 = (chart->h / 2) * -y1 / oscope->vert_max;
y0 += chart->h / 2;
y1 += chart->h / 2;
gdk_draw_line(chart->pixmap, gkrellmss->gc, x, y1, x, y0);
flimit += oscope->samples_per_point;
}
gkrellmss->buf_index = 0;
gkrellmss->buf_count = 0;
}
static void
draw_oscope_grid(void)
{
GdkImage *grid_image;
GdkGC *gc;
GdkColor color;
GkrellmChart *chart = gkrellmss->chart;
gint w, h, x, dx;
/* Draw grid lines on bg_src_pixmap so gkrellm_clear_chart_pixmap()
| will include grid lines.
*/
gkrellm_clean_bg_src_pixmap(chart);
gkrellm_draw_chart_grid_line(chart, chart->bg_src_pixmap, chart->h / 4);
gkrellm_draw_chart_grid_line(chart, chart->bg_src_pixmap, chart->h / 2);
gkrellm_draw_chart_grid_line(chart, chart->bg_src_pixmap, 3 * chart->h/4);
/* There is no vertical grid image, so I make a vertical grid line using
| pixel values from the horizontal grid image at desired x positions.
*/
gdk_drawable_get_size(chart->bg_grid_pixmap, &w, &h);
grid_image = gdk_image_get(chart->bg_grid_pixmap, 0, 0, w, h);
gc = gkrellm_draw_GC(3);
dx = chart->w / HORIZONTAL_DIVS;
for (x = dx; x < HORIZONTAL_DIVS * dx; x += dx)
{
color.pixel = gdk_image_get_pixel(grid_image, x, 0);
gdk_gc_set_foreground(gc, &color);
gdk_draw_line(chart->bg_src_pixmap, gc, x - 1, 0, x - 1, chart->h - 1);
if (h > 1)
{
color.pixel = gdk_image_get_pixel(grid_image, x, 1);
gdk_gc_set_foreground(gc, &color);
gdk_draw_line(chart->bg_src_pixmap, gc, x, 0, x, chart->h - 1);
}
}
gdk_image_destroy(grid_image);
}
static void
draw_oscope_label_decals(void)
{
gchar buf[32];
if (oscope->usec_per_div >= 1000)
sprintf(buf, "%d msec", oscope->usec_per_div / 1000);
else
sprintf(buf, "%d usec", oscope->usec_per_div);
gkrellm_draw_decal_text(NULL, gkrellmss->label0_decal, buf, -1);
}
static void
draw_oscope_labels(void)
{
GkrellmChart *chart = gkrellmss->chart;
if (gkrellmss->show_tip)
return;
if (gkrellmss->stream_open && gkrellmss->extra_info)
{
draw_oscope_label_decals();
gkrellm_draw_decal_on_chart(chart, gkrellmss->label0_decal, 2,
chart->h - gkrellmss->label0_decal->h);
}
}
void
gkrellmss_oscope_horizontal_scaling(void)
{
GkrellmChart *chart = gkrellmss->chart;
oscope->t_sample = 1 / (gfloat) SAMPLE_RATE;
oscope->dx_per_point = 0;
do
{
++oscope->dx_per_point;
oscope->t_trace = (gfloat) oscope->usec_per_div * 1e-6;
oscope->t_trace *= HORIZONTAL_DIVS;
oscope->samples_per_point = oscope->t_trace / oscope->t_sample
/ (gfloat) chart->w * (gfloat) oscope->dx_per_point;
}
while (oscope->samples_per_point < 1);
}
void
gkrellmss_oscope_trace(gint channel)
{
if (oscope->dx_per_point > 1)
draw_oscope_line_trace(channel);
else
draw_oscope_bar_trace(channel);
}
void
gkrellmss_draw_oscope(gboolean force_reset, gboolean draw_grid)
{
GkrellmChart *chart = gkrellmss->chart;
gint y;
if (draw_grid)
draw_oscope_grid();
if (!gkrellmss->streaming)
{
if (!oscope->reset || force_reset)
{
y = chart->h / 2;
gkrellm_clear_chart_pixmap(chart);
gdk_gc_set_foreground(gkrellmss->gc, gkrellm_in_color());
gdk_draw_line(chart->pixmap, gkrellmss->gc, 0, y, chart->w - 1, y);
draw_oscope_labels();
}
gkrellmss->buf_count = 0;
gkrellmss->buf_index = 0;
oscope->x_append = oscope->y_append = 0;
oscope->reset = TRUE;
return;
}
else if (!oscope->x_append && gkrellmss->buf_count)
{
gkrellm_clear_chart_pixmap(chart); /* Draws the grid */
trigger_delay(CHANNEL_LR);
gkrellmss_oscope_trace(CHANNEL_LR);
draw_oscope_labels();
oscope->reset = FALSE;
}
}
Oscope *
gkrellmss_init_oscope(void)
{
oscope = g_new0(Oscope, 1);
oscope->usec_per_div = 2000;
oscope->vert_max = (gint) (gkrellmss->vert_sensitivity * 32767.0);
return oscope;
}