[SCM] calf/master: + Curve: implement (unfinished - no way to set the curve from outside yet) + Keyboard: partially implement (most functionality is actually missing)

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:37:25 UTC 2013


The following commit has been merged in the master branch:
commit 334ade8c62cdf6577d098575fed193aedc3f24e8
Author: kfoltman <kfoltman at 78b06b96-2940-0410-b7fc-879d825d01d8>
Date:   Wed Jul 30 23:00:44 2008 +0000

    + Curve: implement (unfinished - no way to set the curve from outside yet)
    + Keyboard: partially implement (most functionality is actually missing)
    
    
    
    git-svn-id: https://calf.svn.sourceforge.net/svnroot/calf/trunk@241 78b06b96-2940-0410-b7fc-879d825d01d8

diff --git a/src/Makefile.am b/src/Makefile.am
index 107bacd..7e03cfe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,7 +55,7 @@ calf_la_LDFLAGS = -rpath $(ladspadir) -avoid-version -module -lexpat -export-sym
 endif
 
 if USE_LV2_GUI
-calflv2gui_la_SOURCES = gui.cpp custom_ctl.cpp modules.cpp giface.cpp monosynth.cpp organ.cpp preset.cpp synth.cpp lv2gui.cpp main_win.cpp
+calflv2gui_la_SOURCES = gui.cpp ctl_curve.cpp ctl_keyboard.cpp custom_ctl.cpp modules.cpp giface.cpp monosynth.cpp organ.cpp preset.cpp synth.cpp lv2gui.cpp main_win.cpp
 if USE_DEBUG
 calflv2gui_la_LDFLAGS = -rpath $(lv2dir) -avoid-version -module -lexpat $(GUI_DEPS_LIBS) 
 else
@@ -67,7 +67,7 @@ libcalfstatic_la_SOURCES = modules.cpp giface.cpp monosynth.cpp organ.cpp osctl.
 libcalfstatic_la_LDFLAGS = -static -lexpat
 
 if USE_GUI
-libcalfgui_la_SOURCES = gui.cpp preset_gui.cpp custom_ctl.cpp osctl.cpp osctlnet.cpp main_win.cpp
+libcalfgui_la_SOURCES = gui.cpp ctl_curve.cpp ctl_keyboard.cpp preset_gui.cpp custom_ctl.cpp osctl.cpp osctlnet.cpp main_win.cpp
 libcalfgui_la_LDFLAGS = -static
 endif
 
diff --git a/src/calf/Makefile.am b/src/calf/Makefile.am
index 76c4482..b150dc8 100644
--- a/src/calf/Makefile.am
+++ b/src/calf/Makefile.am
@@ -1,6 +1,7 @@
 calfdir = $(includedir)/calf
 
 calf_HEADERS = audio_fx.h benchmark.h biquad.h buffer.h custom_ctl.h \
+    ctl_curve.h ctl_keyboard.h \
     delay.h fft.h fixed_point.h giface.h gui.h inertia.h \
     jackhost.h lv2_event.h lv2_ui.h lv2_uri_map.h lv2-midiport.h lv2wrap.h \
     main_win.h modules.h modules_dev.h modules_synths.h \
diff --git a/src/calf/ctl_curve.h b/src/calf/ctl_curve.h
new file mode 100644
index 0000000..5a31c19
--- /dev/null
+++ b/src/calf/ctl_curve.h
@@ -0,0 +1,110 @@
+/* Calf DSP Library
+ * Barely started curve editor widget. Standard GtkCurve is
+ * unreliable and deprecated, so I need to make my own.
+ *
+ * Copyright (C) 2008 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef CALF_CTL_CURVE_H
+#define CALF_CTL_CURVE_H
+
+#include <gtk/gtk.h>
+#include <vector>
+
+G_BEGIN_DECLS
+
+#define CALF_TYPE_CURVE          (calf_curve_get_type())
+#define CALF_CURVE(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALF_TYPE_CURVE, CalfCurve))
+#define CALF_IS_CURVE(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALF_TYPE_CURVE))
+#define CALF_CURVE_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass),  CALF_TYPE_CURVE, CalfCurveClass))
+#define CALF_IS_CURVE_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass),  CALF_TYPE_CURVE))
+
+struct CalfCurve
+{
+    typedef std::pair<float, float> point;
+    typedef std::vector<point> point_vector;
+    
+    struct EventSink
+    {
+        virtual void curve_changed(const point_vector &data) = 0;
+    };
+
+    struct EventAdapter: public EventSink
+    {
+        virtual void curve_changed(const point_vector &data) {}
+    };
+
+    struct EventTester: public EventSink
+    {
+        virtual void curve_changed(const point_vector &data) {
+            for(size_t i = 0; i < data.size(); i++)
+                g_message("Point %d: (%f, %f)", (int)i, data[i].first, data[i].second);
+        }
+    };
+
+    GtkWidget parent;
+    point_vector *points;
+    float x0, y0, x1, y1;
+    int cur_pt;
+    bool hide_current;
+    EventSink *sink;
+    
+    void log2phys(float &x, float &y) {
+        x = (x - x0) / (x1 - x0) * (parent.allocation.width - 2) + 1;
+        y = (y - y0) / (y1 - y0) * (parent.allocation.height - 2) + 1;
+    }
+    void phys2log(float &x, float &y) {
+        x = x0 + (x - 1) * (x1 - x0) / (parent.allocation.width - 2);
+        y = y0 + (y - 1) * (y1 - y0) / (parent.allocation.height - 2);
+    }
+    void clip(int pt, float &x, float &y, bool &hide)
+    {
+        float ymin = std::min(y0, y1), ymax = std::max(y0, y1);
+        float yamp = ymax - ymin;
+        hide = false;
+        if (pt != 0 && pt != (int)(points->size() - 1))
+        {
+            if (y < ymin - yamp || y > ymax + yamp)
+                hide = true;
+        }
+        if (x < x0) x = x0;
+        if (y < ymin) y = ymin;
+        if (x > x1) x = x1;
+        if (y > ymax) y = ymax;
+        if (pt == 0) x = 0;
+        if (pt == (int)(points->size() - 1))
+            x = (*points)[pt].first;
+        if (pt > 0 && x < (*points)[pt - 1].first)
+            x = (*points)[pt - 1].first;
+        if (pt < (int)(points->size() - 1) && x > (*points)[pt + 1].first)
+            x = (*points)[pt + 1].first;
+    }
+};
+
+struct CalfCurveClass
+{
+    GtkWidgetClass parent_class;
+};
+
+extern GtkWidget *calf_curve_new();
+
+extern GType calf_curve_get_type();
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/calf/ctl_keyboard.h b/src/calf/ctl_keyboard.h
new file mode 100644
index 0000000..7e47051
--- /dev/null
+++ b/src/calf/ctl_keyboard.h
@@ -0,0 +1,74 @@
+/* Calf DSP Library
+ * Barely started keyboard widget. Planned to be usable as
+ * a ruler for curves, and possibly as input widget in future 
+ * as well (that's what event sink interface is for, at least).
+ *
+ * Copyright (C) 2008 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef CALF_CTL_KEYBOARD_H
+#define CALF_CTL_KEYBOARD_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define CALF_TYPE_KEYBOARD          (calf_keyboard_get_type())
+#define CALF_KEYBOARD(obj)          (G_TYPE_CHECK_INSTANCE_CAST ((obj), CALF_TYPE_KEYBOARD, CalfKeyboard))
+#define CALF_IS_KEYBOARD(obj)       (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CALF_TYPE_KEYBOARD))
+#define CALF_KEYBOARD_CLASS(klass)  (G_TYPE_CHECK_CLASS_CAST ((klass),  CALF_TYPE_KEYBOARD, CalfKeyboardClass))
+#define CALF_IS_KEYBOARD_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((klass),  CALF_TYPE_KEYBOARD))
+
+struct CalfKeyboard
+{
+    struct EventSink
+    {
+        virtual void note_on(int note, int vel) = 0;
+        virtual void note_off(int note) = 0;
+    };
+
+    struct EventAdapter: public EventSink
+    {
+        virtual void note_on(int note, int vel) {}
+        virtual void note_off(int note) {}
+    };
+
+    struct EventTester: public EventSink
+    {
+        virtual void note_on(int note, int vel) { g_message("note on %d %d", note, vel); }
+        virtual void note_off(int note) { g_message("note off %d", note); }
+    };
+
+    GtkWidget parent;
+    int nkeys;
+    EventSink *sink;
+    int last_key;
+};
+
+struct CalfKeyboardClass
+{
+    GtkWidgetClass parent_class;
+};
+
+extern GtkWidget *calf_keyboard_new();
+
+extern GType calf_keyboard_get_type();
+
+G_END_DECLS
+
+#endif
+
diff --git a/src/ctl_curve.cpp b/src/ctl_curve.cpp
new file mode 100644
index 0000000..21a4afd
--- /dev/null
+++ b/src/ctl_curve.cpp
@@ -0,0 +1,268 @@
+/* Calf DSP Library
+ * Barely started curve editor widget. Standard GtkCurve is
+ * unreliable and deprecated, so I need to make my own.
+ *
+ * Copyright (C) 2008 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <calf/ctl_curve.h>
+#include <malloc.h>
+#include <stdint.h>
+#include <math.h>
+
+GtkWidget *
+calf_curve_new()
+{
+    GtkWidget *widget = GTK_WIDGET( g_object_new (CALF_TYPE_CURVE, NULL ));
+    return widget;
+}
+
+static gboolean
+calf_curve_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    
+    CalfCurve *self = CALF_CURVE(widget);
+    GdkWindow *window = widget->window;
+    cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(window));
+    GdkColor scHot = { 0, 65535, 0, 0 };
+    GdkColor scPoint = { 0, 65535, 65535, 65535 };
+    GdkColor scLine = { 0, 32767, 32767, 32767 };
+    if (self->points->size())
+    {
+        gdk_cairo_set_source_color(c, &scLine);
+        for (size_t i = 0; i < self->points->size(); i++)
+        {
+            const CalfCurve::point &pt = (*self->points)[i];
+            if (i == (size_t)self->cur_pt && self->hide_current)
+                continue;
+            float x = pt.first, y = pt.second;
+            self->log2phys(x, y);
+            if (!i)
+                cairo_move_to(c, x, y);
+            else
+                cairo_line_to(c, x, y);
+        }
+        cairo_stroke(c);
+    }
+    for (size_t i = 0; i < self->points->size(); i++)
+    {
+        if (i == (size_t)self->cur_pt && self->hide_current)
+            continue;
+        const CalfCurve::point &pt = (*self->points)[i];
+        float x = pt.first, y = pt.second;
+        self->log2phys(x, y);
+        gdk_cairo_set_source_color(c, (i == (size_t)self->cur_pt) ? &scHot : &scPoint);
+        cairo_rectangle(c, x - 2, y - 2, 5, 5);
+        cairo_fill(c);
+    }
+    cairo_destroy(c);
+
+    return TRUE;
+}
+
+static void
+calf_curve_realize(GtkWidget *widget)
+{
+    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+
+    GdkWindowAttr attributes;
+    attributes.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON1_MOTION_MASK | 
+        GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | 
+        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
+    attributes.x = widget->allocation.x;
+    attributes.y = widget->allocation.y;
+    attributes.width = widget->allocation.width;
+    attributes.height = widget->allocation.height;
+    attributes.wclass = GDK_INPUT_OUTPUT;
+    attributes.window_type = GDK_WINDOW_CHILD;
+
+    widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, GDK_WA_X | GDK_WA_Y);
+
+    gdk_window_set_user_data(widget->window, widget);
+    widget->style = gtk_style_attach(widget->style, widget->window);
+}
+
+static void
+calf_curve_size_request (GtkWidget *widget,
+                           GtkRequisition *requisition)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    
+    requisition->width = 64;
+    requisition->height = 32;
+}
+
+static void
+calf_curve_size_allocate (GtkWidget *widget,
+                           GtkAllocation *allocation)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    
+    widget->allocation = *allocation;
+    
+    if (GTK_WIDGET_REALIZED(widget))
+        gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height );
+}
+
+static gboolean
+calf_curve_button_press (GtkWidget *widget, GdkEventButton *event)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    CalfCurve *self = CALF_CURVE(widget);
+    float dist = 5;
+    int found_pt = -1, insert_pt = -1;
+    int i;
+    for (i = 0; i < (int)self->points->size(); i++)
+    {
+        float x = (*self->points)[i].first, y = (*self->points)[i].second;
+        self->log2phys(x, y);
+        float thisdist = std::max(fabs(event->x - x), fabs(event->y - y));
+        if (thisdist < dist)
+        {
+            dist = thisdist;
+            found_pt = i;
+        }
+        if (event->x > x)
+            insert_pt = i + 1;
+    }
+    if (found_pt == -1 && insert_pt != -1)
+    {
+        float x = event->x, y = event->y;
+        bool hide = false;
+        self->phys2log(x, y);
+        self->points->insert(self->points->begin() + insert_pt, CalfCurve::point(x, y));
+        self->clip(insert_pt, x, y, hide);
+        if (hide)
+        {
+            // give up
+            self->points->erase(self->points->begin() + insert_pt);
+            return TRUE;
+        }
+        (*self->points)[insert_pt] = CalfCurve::point(x, y);
+        found_pt = insert_pt;
+    }
+    gtk_widget_grab_focus(widget);
+    self->cur_pt = found_pt;
+    gtk_widget_queue_draw(widget);
+    if (self->sink)
+        self->sink->curve_changed(*self->points);
+    return TRUE;
+}
+
+static gboolean
+calf_curve_button_release (GtkWidget *widget, GdkEventButton *event)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    CalfCurve *self = CALF_CURVE(widget);
+    if (self->cur_pt != -1 && self->hide_current)
+        self->points->erase(self->points->begin() + self->cur_pt);        
+    self->cur_pt = -1;
+    self->hide_current = false;
+    if (self->sink)
+        self->sink->curve_changed(*self->points);
+    gtk_widget_queue_draw(widget);
+    return FALSE;
+}
+
+static gboolean
+calf_curve_pointer_motion (GtkWidget *widget, GdkEventMotion *event)
+{
+    g_assert(CALF_IS_CURVE(widget));
+    CalfCurve *self = CALF_CURVE(widget);
+    if (self->cur_pt != -1)
+    {
+        float x = event->x, y = event->y;
+        self->phys2log(x, y);
+        self->clip(self->cur_pt, x, y, self->hide_current);
+        (*self->points)[self->cur_pt] = CalfCurve::point(x, y);
+        if (self->sink)
+            self->sink->curve_changed(*self->points);
+        gtk_widget_queue_draw(widget);        
+    }
+    return FALSE;
+}
+
+static void
+calf_curve_class_init (CalfCurveClass *klass)
+{
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+    widget_class->realize = calf_curve_realize;
+    widget_class->expose_event = calf_curve_expose;
+    widget_class->size_request = calf_curve_size_request;
+    widget_class->size_allocate = calf_curve_size_allocate;
+    widget_class->button_press_event = calf_curve_button_press;
+    widget_class->button_release_event = calf_curve_button_release;
+    widget_class->motion_notify_event = calf_curve_pointer_motion;
+    // widget_class->key_press_event = calf_curve_key_press;
+    // widget_class->scroll_event = calf_curve_scroll;
+}
+
+static void
+calf_curve_init (CalfCurve *self)
+{
+    GtkWidget *widget = GTK_WIDGET(self);
+    GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self), GTK_CAN_FOCUS);
+    self->points = new CalfCurve::point_vector;
+    // XXXKF: destructor
+    self->points->push_back(CalfCurve::point(0.f, 0.f));
+    self->points->push_back(CalfCurve::point(0.5f, 0.25f));
+    self->points->push_back(CalfCurve::point(1.f, 1.f));
+    self->x0 = 0.f;
+    self->x1 = 1.f;
+    self->y0 = 1.f;
+    self->y1 = 0.f;
+    self->cur_pt = -1;
+    self->hide_current = false;
+}
+
+GType
+calf_curve_get_type (void)
+{
+    static GType type = 0;
+    if (!type) {
+        
+        static const GTypeInfo type_info = {
+            sizeof(CalfCurveClass),
+            NULL, /* base_init */
+            NULL, /* base_finalize */
+            (GClassInitFunc)calf_curve_class_init,
+            NULL, /* class_finalize */
+            NULL, /* class_data */
+            sizeof(CalfCurve),
+            0,    /* n_preallocs */
+            (GInstanceInitFunc)calf_curve_init
+        };
+        
+        for (int i = 0; ; i++) {
+            char *name = g_strdup_printf("CalfCurve%u%d", 
+                ((unsigned int)(intptr_t)calf_curve_class_init) >> 16, i);
+            if (g_type_from_name(name)) {
+                free(name);
+                continue;
+            }
+            type = g_type_register_static(GTK_TYPE_WIDGET,
+                                          name,
+                                          &type_info,
+                                          (GTypeFlags)0);
+            free(name);
+            break;
+        }
+    }
+    return type;
+}
+
diff --git a/src/ctl_keyboard.cpp b/src/ctl_keyboard.cpp
new file mode 100644
index 0000000..3edd427
--- /dev/null
+++ b/src/ctl_keyboard.cpp
@@ -0,0 +1,259 @@
+/* Calf DSP Library
+ * Barely started keyboard widget. Planned to be usable as
+ * a ruler for curves, and possibly as input widget in future 
+ * as well (that's what event sink interface is for, at least).
+ *
+ * Copyright (C) 2008 Krzysztof Foltman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <calf/ctl_keyboard.h>
+#include <stdint.h>
+#include <malloc.h>
+
+GtkWidget *
+calf_keyboard_new()
+{
+    GtkWidget *widget = GTK_WIDGET( g_object_new (CALF_TYPE_KEYBOARD, NULL ));
+    return widget;
+}
+
+static gboolean
+calf_keyboard_expose (GtkWidget *widget, GdkEventExpose *event)
+{
+    g_assert(CALF_IS_KEYBOARD(widget));
+    
+    GdkColor scWhiteKey = { 0, 65535, 65535, 65535 };
+    GdkColor scBlackKey = { 0, 0, 0, 0 };
+    GdkColor scOutline = { 0, 0, 0, 0 };
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    GdkWindow *window = widget->window;
+    cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(window));
+    int sy = widget->allocation.height - 1;
+    cairo_set_line_join(c, CAIRO_LINE_JOIN_MITER);
+    cairo_set_line_width(c, 1);
+    
+    for (int i = 0; i < self->nkeys; i++)
+    {
+        cairo_rectangle(c, 0.5 + 12 * i, 0.5, 12, sy);
+        gdk_cairo_set_source_color(c, &scWhiteKey);
+        cairo_fill_preserve(c);
+        gdk_cairo_set_source_color(c, &scOutline);
+        cairo_stroke(c);
+    }
+
+    for (int i = 0; i < self->nkeys - 1; i++)
+    {
+        if ((1 << (i % 7)) & 59)
+        {
+            cairo_rectangle(c, 8 + 12 * i, 0, 8, sy * 3 / 5);
+            gdk_cairo_set_source_color(c, &scBlackKey);
+            cairo_fill(c);
+        }
+    }
+    
+    cairo_destroy(c);
+
+    return TRUE;
+}
+
+static void
+calf_keyboard_realize(GtkWidget *widget)
+{
+    GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+
+    GdkWindowAttr attributes;
+    attributes.event_mask = GDK_EXPOSURE_MASK | GDK_BUTTON1_MOTION_MASK | 
+        GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | 
+        GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK;
+    attributes.x = widget->allocation.x;
+    attributes.y = widget->allocation.y;
+    attributes.width = widget->allocation.width;
+    attributes.height = widget->allocation.height;
+    attributes.wclass = GDK_INPUT_OUTPUT;
+    attributes.window_type = GDK_WINDOW_CHILD;
+
+    widget->window = gdk_window_new(gtk_widget_get_parent_window (widget), &attributes, GDK_WA_X | GDK_WA_Y);
+
+    gdk_window_set_user_data(widget->window, widget);
+    widget->style = gtk_style_attach(widget->style, widget->window);
+}
+
+static void
+calf_keyboard_size_request (GtkWidget *widget,
+                           GtkRequisition *requisition)
+{
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    g_assert(CALF_IS_KEYBOARD(widget));
+    
+    requisition->width = 12 * self->nkeys + 1;
+    requisition->height = 32;
+}
+
+static void
+calf_keyboard_size_allocate (GtkWidget *widget,
+                           GtkAllocation *allocation)
+{
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    g_assert(CALF_IS_KEYBOARD(widget));
+    widget->allocation = *allocation;
+    widget->allocation.width = widget->requisition.width;
+    
+    if (GTK_WIDGET_REALIZED(widget))
+        gdk_window_move_resize(widget->window, 
+            allocation->x + (allocation->width - widget->allocation.width) / 2, allocation->y, 
+            widget->allocation.width, allocation->height );
+}
+
+static gboolean
+calf_keyboard_key_press (GtkWidget *widget, GdkEventKey *event)
+{
+    g_assert(CALF_IS_KEYBOARD(widget));
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    if (!self->sink)
+        return FALSE;
+    return FALSE;
+}
+
+static int
+calf_keyboard_pos_to_note (CalfKeyboard *kb, int x, int y, int *vel = NULL)
+{
+    // first try black keys
+    if (y <= kb->parent.allocation.height * 3 / 5 && x >= 0 && (x - 8) % 12 < 8)
+    {
+        int blackkey = (x - 8) / 12;
+        if (blackkey < kb->nkeys && (59 & (1 << (blackkey % 7))))
+        {
+            static const int semitones[] = { 1, 3, -1, 6, 8, 10, -1 };
+            return semitones[blackkey % 7] + 12 * (blackkey / 7);
+        }
+    }
+    // if not a black key, then which white one?
+    static const int semitones[] = { 0, 2, 4, 5, 7, 9, 11 };
+    int whitekey = x / 12;
+    // semitones within octave + 12 semitones per octave
+    return semitones[whitekey % 7] + 12 * (whitekey / 7);
+}
+
+static gboolean
+calf_keyboard_button_press (GtkWidget *widget, GdkEventButton *event)
+{
+    g_assert(CALF_IS_KEYBOARD(widget));
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    if (!self->sink)
+        return FALSE;
+    gtk_widget_grab_focus(widget);
+    int vel = 127;
+    self->last_key = calf_keyboard_pos_to_note(self, event->x, event->y, &vel);
+    if (self->last_key != -1)
+        self->sink->note_on(self->last_key, vel);
+    return FALSE;
+}
+
+static gboolean
+calf_keyboard_button_release (GtkWidget *widget, GdkEventButton *event)
+{
+    g_assert(CALF_IS_KEYBOARD(widget));
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    if (!self->sink)
+        return FALSE;
+    if (self->last_key != -1)
+        self->sink->note_off(self->last_key);
+    return FALSE;
+}
+
+static gboolean
+calf_keyboard_pointer_motion (GtkWidget *widget, GdkEventMotion *event)
+{
+    g_assert(CALF_IS_KEYBOARD(widget));
+    CalfKeyboard *self = CALF_KEYBOARD(widget);
+    if (!self->sink)
+        return FALSE;
+    int vel = 127;
+    int key = calf_keyboard_pos_to_note(self, event->x, event->y, &vel);
+    if (key != self->last_key)
+    {
+        if (self->last_key != -1)
+            self->sink->note_off(self->last_key);
+        self->last_key = key;
+        if (self->last_key != -1)
+            self->sink->note_on(self->last_key, vel);
+    }
+    return FALSE;
+}
+
+static void
+calf_keyboard_class_init (CalfKeyboardClass *klass)
+{
+    GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+    widget_class->realize = calf_keyboard_realize;
+    widget_class->size_allocate = calf_keyboard_size_allocate;
+    widget_class->expose_event = calf_keyboard_expose;
+    widget_class->size_request = calf_keyboard_size_request;
+    widget_class->button_press_event = calf_keyboard_button_press;
+    widget_class->button_release_event = calf_keyboard_button_release;
+    widget_class->motion_notify_event = calf_keyboard_pointer_motion;
+    widget_class->key_press_event = calf_keyboard_key_press;
+    // widget_class->scroll_event = calf_keyboard_scroll;
+}
+
+static void
+calf_keyboard_init (CalfKeyboard *self)
+{
+    GtkWidget *widget = GTK_WIDGET(self);
+    g_assert(CALF_IS_KEYBOARD(widget));
+    GTK_WIDGET_SET_FLAGS (GTK_WIDGET(self), GTK_CAN_FOCUS);
+    self->nkeys = 7 * 3 + 1;
+    self->sink = NULL;
+    self->last_key = -1;
+}
+
+GType
+calf_keyboard_get_type (void)
+{
+    static GType type = 0;
+    if (!type) {
+        
+        static const GTypeInfo type_info = {
+            sizeof(CalfKeyboardClass),
+            NULL, /* base_init */
+            NULL, /* base_finalize */
+            (GClassInitFunc)calf_keyboard_class_init,
+            NULL, /* class_finalize */
+            NULL, /* class_data */
+            sizeof(CalfKeyboard),
+            0,    /* n_preallocs */
+            (GInstanceInitFunc)calf_keyboard_init
+        };
+        
+        for (int i = 0; ; i++) {
+            char *name = g_strdup_printf("CalfKeyboard%u%d", 
+                ((unsigned int)(intptr_t)calf_keyboard_class_init) >> 16, i);
+            if (g_type_from_name(name)) {
+                free(name);
+                continue;
+            }
+            type = g_type_register_static(GTK_TYPE_WIDGET,
+                                          name,
+                                          &type_info,
+                                          (GTypeFlags)0);
+            free(name);
+            break;
+        }
+    }
+    return type;
+}
+

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list