svcore  1.9
FlexiNoteModel.h
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #ifndef _FLEXINOTE_MODEL_H_
00017 #define _FLEXINOTE_MODEL_H_
00018 
00019 #include "IntervalModel.h"
00020 #include "NoteData.h"
00021 #include "base/RealTime.h"
00022 #include "base/Pitch.h"
00023 #include "base/PlayParameterRepository.h"
00024 
00042 struct FlexiNote
00043 {
00044 public:
00045     FlexiNote(long _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { }
00046     FlexiNote(long _frame, float _value, int _duration, float _level, QString _label) :
00047         frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { }
00048 
00049     int getDimensions() const { return 3; }
00050 
00051     long frame;
00052     float value;
00053     int duration;
00054     float level;
00055     QString label;
00056 
00057     QString getLabel() const { return label; }
00058     
00059     void toXml(QTextStream &stream,
00060                QString indent = "",
00061                QString extraAttributes = "") const
00062     {
00063         stream <<
00064             QString("%1<point frame=\"%2\" value=\"%3\" duration=\"%4\" level=\"%5\" label=\"%6\" %7/>\n")
00065             .arg(indent).arg(frame).arg(value).arg(duration).arg(level)
00066             .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes);
00067     }
00068 
00069     QString toDelimitedDataString(QString delimiter, int sampleRate) const
00070     {
00071         QStringList list;
00072         list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
00073         list << QString("%1").arg(value);
00074         list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str();
00075         list << QString("%1").arg(level);
00076         if (label != "") list << label;
00077         return list.join(delimiter);
00078     }
00079 
00080     struct Comparator {
00081         bool operator()(const FlexiNote &p1,
00082                         const FlexiNote &p2) const {
00083             if (p1.frame != p2.frame) return p1.frame < p2.frame;
00084             if (p1.value != p2.value) return p1.value < p2.value;
00085             if (p1.duration != p2.duration) return p1.duration < p2.duration;
00086             if (p1.level != p2.level) return p1.level < p2.level;
00087             return p1.label < p2.label;
00088         }
00089     };
00090     
00091     struct OrderComparator {
00092         bool operator()(const FlexiNote &p1,
00093                         const FlexiNote &p2) const {
00094             return p1.frame < p2.frame;
00095         }
00096     };
00097 };
00098 
00099 
00100 class FlexiNoteModel : public IntervalModel<FlexiNote>, public NoteExportable
00101 {
00102     Q_OBJECT
00103     
00104 public:
00105     FlexiNoteModel(int sampleRate, int resolution,
00106               bool notifyOnAdd = true) :
00107         IntervalModel<FlexiNote>(sampleRate, resolution, notifyOnAdd),
00108         m_valueQuantization(0)
00109     {
00110         PlayParameterRepository::getInstance()->addPlayable(this);
00111     }
00112 
00113     FlexiNoteModel(int sampleRate, int resolution,
00114               float valueMinimum, float valueMaximum,
00115               bool notifyOnAdd = true) :
00116         IntervalModel<FlexiNote>(sampleRate, resolution,
00117                             valueMinimum, valueMaximum,
00118                             notifyOnAdd),
00119         m_valueQuantization(0)
00120     {
00121         PlayParameterRepository::getInstance()->addPlayable(this);
00122     }
00123 
00124     virtual ~FlexiNoteModel()
00125     {
00126         PlayParameterRepository::getInstance()->removePlayable(this);
00127     }
00128 
00129     float getValueQuantization() const { return m_valueQuantization; }
00130     void setValueQuantization(float q) { m_valueQuantization = q; }
00131     float getValueMinimum() const { return 33; }
00132     float getValueMaximum() const { return 88; }
00133 
00134     QString getTypeName() const { return tr("FlexiNote"); }
00135 
00136     virtual bool canPlay() const { return true; }
00137 
00138     virtual QString getDefaultPlayClipId() const
00139     {
00140         return "elecpiano";
00141     }
00142 
00143     virtual void toXml(QTextStream &out,
00144                        QString indent = "",
00145                        QString extraAttributes = "") const
00146     {
00147         std::cerr << "FlexiNoteModel::toXml: extraAttributes = \"" 
00148                   << extraAttributes.toStdString() << std::endl;
00149 
00150         IntervalModel<FlexiNote>::toXml
00151             (out,
00152              indent,
00153              QString("%1 subtype=\"flexinote\" valueQuantization=\"%2\"")
00154              .arg(extraAttributes).arg(m_valueQuantization));
00155     }
00156 
00161     virtual int getColumnCount() const
00162     {
00163         return 6;
00164     }
00165 
00166     virtual QString getHeading(int column) const
00167     {
00168         switch (column) {
00169         case 0: return tr("Time");
00170         case 1: return tr("Frame");
00171         case 2: return tr("Pitch");
00172         case 3: return tr("Duration");
00173         case 4: return tr("Level");
00174         case 5: return tr("Label");
00175         default: return tr("Unknown");
00176         }
00177     }
00178 
00179     virtual QVariant getData(int row, int column, int role) const
00180     {
00181         if (column < 4) {
00182             return IntervalModel<FlexiNote>::getData(row, column, role);
00183         }
00184 
00185         PointListConstIterator i = getPointListIteratorForRow(row);
00186         if (i == m_points.end()) return QVariant();
00187 
00188         switch (column) {
00189         case 4: return i->level;
00190         case 5: return i->label;
00191         default: return QVariant();
00192         }
00193     }
00194 
00195     virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
00196     {
00197         if (column < 4) {
00198             return IntervalModel<FlexiNote>::getSetDataCommand
00199                 (row, column, value, role);
00200         }
00201 
00202         if (role != Qt::EditRole) return 0;
00203         PointListConstIterator i = getPointListIteratorForRow(row);
00204         if (i == m_points.end()) return 0;
00205         EditCommand *command = new EditCommand(this, tr("Edit Data"));
00206 
00207         Point point(*i);
00208         command->deletePoint(point);
00209 
00210         switch (column) {
00211         case 4: point.level = value.toDouble(); break;
00212         case 5: point.label = value.toString(); break;
00213         }
00214 
00215         command->addPoint(point);
00216         return command->finish();
00217     }
00218 
00219     virtual SortType getSortType(int column) const
00220     {
00221         if (column == 5) return SortAlphabetical;
00222         return SortNumeric;
00223     }
00224 
00229     NoteList getNotes() const 
00230     {
00231         return getNotesWithin(getStartFrame(), getEndFrame());
00232     }
00233 
00234     NoteList getNotesWithin(int startFrame, int endFrame) const 
00235     {    
00236         PointList points = getPoints(startFrame, endFrame);
00237         NoteList notes;
00238         for (PointList::iterator pli = points.begin(); pli != points.end(); ++pli) {
00239             int duration = pli->duration;
00240             if (duration == 0 || duration == 1) {
00241                 duration = getSampleRate() / 20;
00242             }
00243             int pitch = lrintf(pli->value);
00244 
00245             int velocity = 100;
00246             if (pli->level > 0.f && pli->level <= 1.f) {
00247                 velocity = lrintf(pli->level * 127);
00248             }
00249 
00250             NoteData note(pli->frame, duration, pitch, velocity);
00251 
00252             if (getScaleUnits() == "Hz") {
00253                 note.frequency = pli->value;
00254                 note.midiPitch = Pitch::getPitchForFrequency(note.frequency);
00255                 note.isMidiPitchQuantized = false;
00256             }
00257             notes.push_back(note);
00258         }
00259         return notes;
00260     }
00261 
00262 protected:
00263     float m_valueQuantization;
00264 };
00265 
00266 #endif