summaryrefslogtreecommitdiff
path: root/muse2/muse/midiedit/scoreedit.h
diff options
context:
space:
mode:
Diffstat (limited to 'muse2/muse/midiedit/scoreedit.h')
-rw-r--r--muse2/muse/midiedit/scoreedit.h831
1 files changed, 658 insertions, 173 deletions
diff --git a/muse2/muse/midiedit/scoreedit.h b/muse2/muse/midiedit/scoreedit.h
index 767dc463..367aac5e 100644
--- a/muse2/muse/midiedit/scoreedit.h
+++ b/muse2/muse/midiedit/scoreedit.h
@@ -1,8 +1,8 @@
//=========================================================
// MusE
// Linux Music Editor
-// $Id: pianoroll.h,v 1.5.2.4 2009/11/16 11:29:33 lunar_shuttle Exp $
-// (C) Copyright 1999 Werner Schweer (ws@seh.de)
+// scoreedit.h
+// (C) Copyright 2011 Florian Jung (florian.a.jung@web.de)
//=========================================================
#ifndef __SCOREEDIT_H__
@@ -12,6 +12,11 @@
#include <QResizeEvent>
#include <QLabel>
#include <QKeyEvent>
+#include <QPainter>
+#include <QPixmap>
+#include <QTimer>
+#include <QScrollBar>
+#include <QSignalMapper>
#include <values.h>
#include "noteinfo.h"
@@ -19,183 +24,663 @@
#include "midieditor.h"
#include "tools.h"
#include "event.h"
+#include "view.h"
+#include "gconfig.h"
+#include "part.h"
+#include "keyevent.h"
-class MidiPart;
-class TimeLabel;
-class PitchLabel;
-class QLabel;
-class PianoCanvas;
-class MTScale;
-class Track;
-class QToolButton;
-class QToolBar;
-class QPushButton;
-class CtrlEdit;
-class Splitter;
-class PartList;
-class Toolbar1;
-class Xml;
-class QuantConfig;
-class ScrollScale;
-class Part;
-class SNode;
-class QMenu;
-class QAction;
-class QWidget;
-class QScrollBar;
-class MidiTrackInfo;
-class QScrollArea;
+#include <set>
+#include <map>
+#include <list>
+#include <vector>
+#include <string>
+
+using std::set;
+using std::pair;
+using std::map;
+using std::list;
+using std::vector;
+using std::string;
+
+
+
+#define TICKS_PER_WHOLE (config.division*4)
+#define SONG_LENGTH (song->len())
+
+
+
+enum {CMD_COLOR_BLACK, CMD_COLOR_VELO, CMD_COLOR_PART,
+ CMD_SET_NAME,
+ CMD_NOTELEN_1, CMD_NOTELEN_2, CMD_NOTELEN_4, CMD_NOTELEN_8,
+ CMD_NOTELEN_16, CMD_NOTELEN_32, CMD_NOTELEN_LAST };
+
+class ScoreCanvas;
//---------------------------------------------------------
-// PianoRoll
+// ScoreEdit
//---------------------------------------------------------
-class ScoreEdit : public MidiEditor {
- Event selEvent;
- MidiPart* selPart;
- int selTick;
-
- //enum { CMD_EVENT_COLOR, CMD_CONFIG_QUANT, CMD_LAST };
- //int menu_ids[CMD_LAST];
- //Q3PopupMenu *menuEdit, *menuFunctions, *menuSelect, *menuConfig, *menuPlugins;
-
-
- QMenu *menuEdit, *menuFunctions, *menuSelect, *menuConfig, *eventColor, *menuPlugins;
- MidiTrackInfo *midiTrackInfo;
- Track* selected;
-
- QAction* editCutAction;
- QAction* editCopyAction;
- QAction* editPasteAction;
- QAction* editDelEventsAction;
-
- QAction* selectAllAction;
- QAction* selectNoneAction;
- QAction* selectInvertAction;
- QAction* selectInsideLoopAction;
- QAction* selectOutsideLoopAction;
- QAction* selectPrevPartAction;
- QAction* selectNextPartAction;
-
- QAction* evColorBlueAction;
- QAction* evColorPitchAction;
- QAction* evColorVelAction;
-
- QAction* funcOverQuantAction;
- QAction* funcNoteOnQuantAction;
- QAction* funcNoteOnOffQuantAction;
- QAction* funcIterQuantAction;
- QAction* funcConfigQuantAction;
- QAction* funcGateTimeAction;
- QAction* funcModVelAction;
- QAction* funcCrescendoAction;
- QAction* funcTransposeAction;
- QAction* funcThinOutAction;
- QAction* funcEraseEventAction;
- QAction* funcNoteShiftAction;
- QAction* funcMoveClockAction;
- QAction* funcCopyMeasureAction;
- QAction* funcEraseMeasureAction;
- QAction* funcDelMeasureAction;
- QAction* funcCreateMeasureAction;
- QAction* funcSetFixedLenAction;
- QAction* funcDelOverlapsAction;
-
-
- int tickOffset;
- int lenOffset;
- int pitchOffset;
- int veloOnOffset;
- int veloOffOffset;
- bool deltaMode;
-
- NoteInfo* info;
- QToolButton* srec;
- QToolButton* midiin;
-
- Toolbar1* toolbar;
- Splitter* splitter;
- Splitter* hsplitter;
- Splitter* ctrlLane;
-
- QToolButton* speaker;
- QToolBar* tools;
- EditToolBar* tools2;
-
- int colorMode;
-
- static int _quantInit, _rasterInit;
- static int _widthInit, _heightInit;
-
- static int _quantStrengthInit;
- static int _quantLimitInit;
- static bool _quantLenInit;
- static int _toInit;
- static int colorModeInit;
-
- int _quantStrength;
- int _quantLimit;
- int _to;
- bool _quantLen;
- QuantConfig* quantConfig;
- bool _playEvents;
-
- //QScrollBar* infoScroll;
- QScrollArea* infoScroll;
-
- Q_OBJECT
- void initShortcuts();
- void setEventColorMode(int);
- QWidget* genToolbar(QWidget* parent);
- virtual void closeEvent(QCloseEvent*);
- virtual void keyPressEvent(QKeyEvent*);
- virtual void resizeEvent(QResizeEvent*);
-
- private slots:
- void setSelection(int, Event&, Part*);
- void noteinfoChanged(NoteInfo::ValType, int);
- //CtrlEdit* addCtrl();
- void removeCtrl(CtrlEdit* ctrl);
- void soloChanged(bool flag);
- //void trackInfoScroll(int);
- void setRaster(int);
- void setQuant(int);
- void configQuant();
- void setQuantStrength(int val) { _quantStrength = val; }
- void setQuantLimit(int val) { _quantLimit = val; }
- void setQuantLen(bool val) { _quantLen = val; }
- void cmd(int);
- void setSteprec(bool);
- void setTo(int val) { _to = val; }
- void eventColorModeChanged(int);
- void clipboardChanged(); // enable/disable "Paste"
- void selectionChanged(); // enable/disable "Copy" & "Paste"
- void setSpeaker(bool);
- void setTime(unsigned);
- void follow(int pos);
- void songChanged1(int);
- void configChanged();
- void newCanvasWidth(int);
- void toggleTrackInfo();
- void updateTrackInfo();
-
- signals:
- void deleted(unsigned long);
-
+class ScoreEdit : public TopWin
+{
+ Q_OBJECT
+
+ private:
+ virtual void closeEvent(QCloseEvent*);
+
+ QGridLayout* mainGrid;
+ QWidget* mainw;
+
+ QScrollBar* xscroll;
+ QScrollBar* yscroll;
+ ScoreCanvas* score_canvas;
+
+ static int serial;
+ static set<QString> names;
+
+ QString name;
+
+ QSignalMapper* menu_mapper;
+
+ bool set_name(QString newname, bool emit_signal=true, bool emergency_name=false);
+
+ private slots:
+ void menu_command(int);
+
+ signals:
+ void deleted(unsigned long);
+ void name_changed();
+
+ public slots:
+ void canvas_width_changed(int);
+ void viewport_width_changed(int);
+ void canvas_height_changed(int);
+ void viewport_height_changed(int);
+
+ public:
+ ScoreEdit(QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT);
+ ~ScoreEdit();
+ static void readConfiguration(Xml&){}; //TODO does nothing
+ static void writeConfiguration(int, Xml&){}; //TODO does nothing
+
+ void add_parts(PartList* pl, bool all_in_one=false);
+ QString get_name() { return name; }
+ };
+
+
+
+
+
+
+enum stem_t
+{
+ UPWARDS,
+ DOWNWARDS
+};
+
+enum vorzeichen_t
+{
+ B=-1,
+ NONE=0,
+ SHARP=1
+};
+
+struct note_pos_t
+{
+ int height; // 0 means "C-line", 1 "D-line" and so on
+ vorzeichen_t vorzeichen;
+
+ bool operator== (const note_pos_t& that) const
+ {
+ return (this->height==that.height) && (this->vorzeichen == that.vorzeichen);
+ }
+};
+
+bool operator< (const note_pos_t& a, const note_pos_t& b);
+
+
+
+
+
+
+
+class FloEvent
+{
+ public:
+ enum typeEnum { NOTE_ON = 30, NOTE_OFF = 10, BAR = 20, KEY_CHANGE=23, TIME_SIG=26 }; //the order matters!
+ typeEnum type;
+ unsigned tick;
+ Part* source_part;
+ Event* source_event;
+
+ int pitch;
+ mutable int vel;
+ mutable int len;
+
+ int num;
+ int denom;
+
+ key_enum key;
+
+
+ FloEvent(unsigned ti, int p,int v,int l,typeEnum t, Part* part=NULL, Event* event=NULL)
+ {
+ pitch=p;
+ vel=v;
+ len=l;
+ type= t;
+ tick=ti;
+ source_event=event;
+ source_part=part;
+ }
+ FloEvent(unsigned ti, typeEnum t, int num_, int denom_)
+ {
+ type=t;
+ num=num_;
+ denom=denom_;
+ tick=ti;
+ source_event=NULL;
+ source_part=NULL;
+ }
+ FloEvent(unsigned ti, typeEnum t, key_enum k)
+ {
+ type=t;
+ key=k;
+ tick=ti;
+ source_event=NULL;
+ source_part=NULL;
+ }
+};
+class FloItem
+{
+ public:
+ enum typeEnum { NOTE=21, REST=22, NOTE_END=01, REST_END=02, BAR =10, KEY_CHANGE=13, TIME_SIG=16}; //the order matters!
+ typeEnum type;
+ unsigned begin_tick;
+ Event* source_event;
+ Part* source_part;
+
+ note_pos_t pos;
+ int len;
+ int dots;
+ bool tied;
+ bool already_grouped;
+
+ int num;
+ int denom;
+
+ key_enum key;
+
+ mutable stem_t stem;
+ mutable int shift;
+ mutable bool ausweich;
+ mutable bool is_tie_dest;
+ mutable int tie_from_x;
+
+ mutable int x;
+ mutable int y;
+ mutable int stem_x;
+ mutable QPixmap* pix;
+
+ mutable bool is_active;
+
+ QRect bbox() const;
+
+
+
+ FloItem(typeEnum t, note_pos_t p, int l=0,int d=0, bool ti=false, unsigned beg=0, Part* part=NULL, Event* event=NULL)
+ {
+ pos=p;
+ dots=d;
+ len=l;
+ type=t;
+ already_grouped=false;
+ tied=ti;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=beg;
+ source_event=event;
+ source_part=part;
+ }
+
+ FloItem(typeEnum t, int num_, int denom_)
+ {
+ type=t;
+ num=num_;
+ denom=denom_;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem(typeEnum t, key_enum k)
+ {
+ type=t;
+ key=k;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem(typeEnum t)
+ {
+ type=t;
+
+ already_grouped=false;
+ tied=false;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ FloItem()
+ {
+ already_grouped=false;
+ tied=false;
+ shift=0;
+ ausweich=false;
+ is_tie_dest=false;
+ begin_tick=-1;
+ source_event=NULL;
+ source_part=NULL;
+ }
+
+ bool operator==(const FloItem& that)
+ {
+ if (this->type != that.type) return false;
+
+ switch(type)
+ {
+ case NOTE:
+ case REST:
+ case NOTE_END:
+ case REST_END:
+ return (this->pos == that.pos);
+
+ //the following may only occurr once in a set
+ //so we don't search for "the time signature with 4/4
+ //at t=0", but only for "some time signature at t=0"
+ //that's why true is returned, and not some conditional
+ //expression
+ case BAR:
+ case KEY_CHANGE:
+ case TIME_SIG:
+ return true;
+ }
+ }
+};
+struct floComp
+{
+ bool operator() (const pair<unsigned, FloEvent>& a, const pair<unsigned, FloEvent>& b )
+ {
+ if (a.first < b.first) return true;
+ if (a.first > b.first) return false;
+
+ if (a.second.type<b.second.type) return true;
+ if (a.second.type>b.second.type) return false;
+
+ return (a.second.pitch<b.second.pitch);
+ }
+ bool operator() (const FloItem& a, const FloItem& b )
+ {
+ if (a.type < b.type) return true;
+ if (a.type > b.type) return false;
+
+ switch(a.type)
+ {
+ case FloItem::NOTE:
+ case FloItem::REST:
+ case FloItem::NOTE_END:
+ case FloItem::REST_END:
+ return (a.pos < b.pos);
+
+ //the following may only occurr once in a set
+ //so we don't search for "the time signature with 4/4
+ //at t=0", but only for "some time signature at t=0"
+ //that's why true is returned, and not some conditional
+ //expression
+ case FloItem::BAR:
+ case FloItem::KEY_CHANGE:
+ case FloItem::TIME_SIG:
+ return false;
+ }
+ return (a.pos < b.pos);
+ }
+};
+
+typedef set< pair<unsigned, FloEvent>, floComp > ScoreEventList;
+typedef map< unsigned, set<FloItem, floComp> > ScoreItemList;
+
+enum clef_t
+{
+ VIOLIN,
+ BASS
+};
+
+
+struct note_len_t
+{
+ int len;
+ int dots;
+
+ note_len_t(int l, int d)
+ {
+ len=l; dots=d;
+ }
+
+ note_len_t(int l)
+ {
+ len=l; dots=0;
+ }
+};
+
+bool operator< (const note_len_t& a,const note_len_t& b);
+
+struct cumulative_t
+{
+ int count;
+ int cumul;
+
+ cumulative_t()
+ {
+ count=0;
+ cumul=0;
+ }
+
+ void add(int v)
+ {
+ count++;
+ cumul+=v;
+ }
+
+ float mean()
+ {
+ return (float)cumul/count;
+ }
+};
+
+#define BLACK_PIXMAP (NUM_PARTCOLORS)
+#define HIGHLIGHTED_PIXMAP (NUM_PARTCOLORS+1)
+#define NUM_MYCOLORS (NUM_PARTCOLORS+2)
+
+struct timesig_t
+{
+ int num;
+ int denom;
+};
+
+enum staff_type_t
+{
+ NORMAL,
+ GRAND_TOP,
+ GRAND_BOTTOM
+};
+
+enum staff_mode_t
+{
+ MODE_TREBLE,
+ MODE_BASS,
+ MODE_BOTH
+};
+
+struct staff_t
+{
+ set<Part*> parts;
+ ScoreEventList eventlist;
+ ScoreItemList itemlist;
+
+ int y_top;
+ int y_draw;
+ int y_bottom;
+
+ staff_type_t type;
+ clef_t clef;
+ int split_note;
+
+ ScoreCanvas* parent;
+
+ void create_appropriate_eventlist();
+ void create_itemlist();
+ void process_itemlist();
+ void calc_item_pos();
+
+ void recalculate()
+ {
+ create_appropriate_eventlist();
+ create_itemlist();
+ process_itemlist();
+ calc_item_pos();
+ }
+
+ staff_t(ScoreCanvas* parent_)
+ {
+ type=NORMAL;
+ clef=VIOLIN;
+ parent=parent_;
+ }
+
+ staff_t (ScoreCanvas* parent_, staff_type_t type_, clef_t clef_, set<Part*> parts_, int split_note_=0)
+ {
+ type=type_;
+ clef=clef_;
+ split_note=split_note_;
+ parts=parts_;
+ parent=parent_;
+ }
+
+ bool cleanup_parts();
+
+ set<Part*> parts_at_tick(unsigned tick);
+};
+
+list<int> calc_accidentials(key_enum key, clef_t clef, key_enum next_key=KEY_C);
+note_pos_t note_pos_(int note, key_enum key);
+note_pos_t note_pos (unsigned note, key_enum key, clef_t clef);
+
+int calc_len(int l, int d);
+list<note_len_t> parse_note_len(int len_ticks, int begin_tick, vector<int>& foo, int quant_power2, bool allow_dots=true, bool allow_normal=true);
+
+int clef_height(clef_t clef);
+
+
+int calc_timesig_width(int num, int denom);
+int calc_number_width(int n);
+
+
+class ScoreCanvas : public View
+{
+ Q_OBJECT
+ private:
+ static void init_pixmaps();
+ static void draw_pixmap(QPainter& p, int x, int y, const QPixmap& pm);
+ static void draw_tie (QPainter& p, int x1, int x4, int yo, bool up=true, QColor color=Qt::black);
+
+ static void draw_accidentials(QPainter& p, int x, int y_offset, const list<int>& acc_list, const QPixmap& pix);
+
+ static void draw_timesig(QPainter& p, int x, int y_offset, int num, int denom);
+
+ static void draw_number(QPainter& p, int x, int y, int n);
+
+
+
+
+
+ static int height_to_pitch(int h, clef_t clef, key_enum key);
+ static int height_to_pitch(int h, clef_t clef);
+ static int y_to_height(int y);
+ int y_to_pitch(int y, int t, clef_t clef);
+
+
+
+
+ void draw_note_lines(QPainter& p, int y);
+ void draw_preamble(QPainter& p, int y, clef_t clef);
+ void draw_items(QPainter& p, int y, staff_t& staff, ScoreItemList::iterator from_it, ScoreItemList::iterator to_it);
+ void draw_items(QPainter& p, int y, staff_t& staff, int x1, int x2);
+ void draw_items(QPainter& p, int y, staff_t& staff);
+ void calc_pos_add_list();
+
+
+ void recalc_staff_pos();
+ list<staff_t>::iterator staff_at_y(int y);
+
+
+ timesig_t timesig_at_tick(int t);
+ key_enum key_at_tick(int t);
+ int tick_to_x(int t);
+ int x_to_tick(int x);
+ int calc_posadd(int t);
+
+
+
+ bool need_redraw_for_hilighting(ScoreItemList::iterator from_it, ScoreItemList::iterator to_it);
+ bool need_redraw_for_hilighting(ScoreItemList& itemlist, int x1, int x2);
+ bool need_redraw_for_hilighting(ScoreItemList& itemlist);
+ bool need_redraw_for_hilighting();
+
+
+ void set_staffmode(list<staff_t>::iterator it, staff_mode_t mode);
+ void remove_staff(list<staff_t>::iterator it);
+ void merge_staves(list<staff_t>::iterator dest, list<staff_t>::iterator src);
+ void cleanup_staves();
+ void maybe_close_if_empty();
+
+// member variables ---------------------------------------------------
+ int _quant_power2;
+ int _pixels_per_whole;
+
+ std::map<int,int> pos_add_list;
+
+ list<staff_t> staves;
+
+ // the drawing area is split into a "preamble" containing clef,
+ // key and time signature, and the "item's area" containing the
+ // actual items (notes, bars, rests, etc.)
+ // x_pos is responsible for scrolling. an item with item->x==x_pos
+ // will be drawn exactly at the left beginning of the item's area
+ // x_left could also be called "preamble's width". it defines
+ // where the item's area begins
+ // when multiple note systems are drawn into one window, the
+ // preamble's length is the same for each system
+ int x_pos;
+ int x_left;
+
+ int y_pos;
+
+ //for mouse-scrolling
+ float x_scroll_speed;
+ float x_scroll_pos;
+ float y_scroll_speed;
+ float y_scroll_pos;
+
+ Part* selected_part;
+ int last_len;
+ int new_len; //when zero or negative, last_len is used
+
+ QPoint mouse_down_pos;
+ bool mouse_down;
+ enum operation_t
+ {
+ NO_OP=0,
+ BEGIN=1,
+ LENGTH=2,
+ PITCH=3
+ };
+ operation_t mouse_operation;
+ operation_t mouse_x_drag_operation;
+ bool mouse_erases_notes;
+ bool mouse_inserts_notes;
+
+ bool dragging;
+ Part* dragged_event_part;
+ Event dragged_event;
+ int dragged_event_original_pitch;
+
+
+
+ enum {COLOR_MODE_BLACK, COLOR_MODE_PART, COLOR_MODE_PITCH} coloring_mode;
+ bool preamble_contains_keysig;
+ bool preamble_contains_timesig;
+
+
+ //menu stuff
+ QAction* staffmode_treble_action;
+ QAction* staffmode_bass_action;
+ QAction* staffmode_both_action;
+ QAction* remove_staff_action;
+
+ QMenu* staff_menu;
+ list<staff_t>::iterator current_staff;
+ bool dragging_staff;
+
+
+ private slots:
+ void staffmode_treble_slot();
+ void staffmode_bass_slot();
+ void staffmode_both_slot();
+ void remove_staff_slot();
+
+ void play_changed(bool);
+ void config_changed();
+
public slots:
- virtual void updateHScrollRange();
- void execDeliveredScript(int id);
- void execUserScript(int id);
- CtrlEdit* addCtrl();
-
- public:
- ScoreEdit(PartList*, QWidget* parent = 0, const char* name = 0, unsigned initPos = MAXINT);
- ~ScoreEdit();
- virtual void readStatus(Xml&);
- virtual void writeStatus(int, Xml&) const;
- static void readConfiguration(Xml&);
- static void writeConfiguration(int, Xml&);
- };
+ void x_scroll_event(int);
+ void y_scroll_event(int);
+ void song_changed(int);
+ void goto_tick(int,bool);
+ void pos_changed(int i, unsigned u, bool b);
+ void heartbeat_timer_event();
+
+ void set_tool(int);
+ void set_quant(int);
+ void menu_command(int);
+ void preamble_keysig_slot(bool);
+ void preamble_timesig_slot(bool);
+ void set_pixels_per_whole(int);
+
+ signals:
+ void xscroll_changed(int);
+ void yscroll_changed(int);
+ void viewport_width_changed(int);
+ void canvas_width_changed(int);
+ void viewport_height_changed(int);
+ void canvas_height_changed(int);
+ void pixels_per_whole_changed(int);
+
+ protected:
+ virtual void draw(QPainter& p, const QRect& rect);
+ ScoreEdit* parent;
+
+ virtual void mousePressEvent (QMouseEvent* event);
+ virtual void mouseMoveEvent (QMouseEvent* event);
+ virtual void mouseReleaseEvent (QMouseEvent* event);
+ virtual void resizeEvent(QResizeEvent*);
+
+ public:
+ ScoreCanvas(ScoreEdit*, QWidget*, int, int);
+ ~ScoreCanvas(){};
+
+ void add_staves(PartList* pl, bool all_in_one);
+
+ int canvas_width();
+ int canvas_height();
+ int viewport_width();
+ int viewport_height();
+
+ int quant_power2() { return _quant_power2; }
+ int quant_len() { return (1<<_quant_power2); }
+ int quant_ticks() { return TICKS_PER_WHOLE / (1<<_quant_power2); }
+ int pixels_per_whole() { return _pixels_per_whole; }
+ int note_x_indent() { return pixels_per_whole()/quant_len()/2; }
+};
+
+int calc_measure_len(const list<int>& nums, int denom);
+vector<int> create_emphasize_list(const list<int>& nums, int denom);
+vector<int> create_emphasize_list(int num, int denom);
+
#endif