svcore  1.9
NoteModel.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 _NOTE_MODEL_H_
00017 #define _NOTE_MODEL_H_
00018 
00019 #include "IntervalModel.h"
00020 #include "NoteData.h"
00021 #include "base/RealTime.h"
00022 #include "base/PlayParameterRepository.h"
00023 #include "base/Pitch.h"
00024 
00038 struct Note
00039 {
00040 public:
00041     Note(long _frame) : frame(_frame), value(0.0f), duration(0), level(1.f) { }
00042     Note(long _frame, float _value, int _duration, float _level, QString _label) :
00043         frame(_frame), value(_value), duration(_duration), level(_level), label(_label) { }
00044 
00045     int getDimensions() const { return 3; }
00046 
00047     long frame;
00048     float value;
00049     int duration;
00050     float level;
00051     QString label;
00052 
00053     QString getLabel() const { return label; }
00054     
00055     void toXml(QTextStream &stream,
00056                QString indent = "",
00057                QString extraAttributes = "") const
00058     {
00059         stream <<
00060             QString("%1<point frame=\"%2\" value=\"%3\" duration=\"%4\" level=\"%5\" label=\"%6\" %7/>\n")
00061             .arg(indent).arg(frame).arg(value).arg(duration).arg(level)
00062             .arg(XmlExportable::encodeEntities(label)).arg(extraAttributes);
00063     }
00064 
00065     QString toDelimitedDataString(QString delimiter, int sampleRate) const
00066     {
00067         QStringList list;
00068         list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
00069         list << QString("%1").arg(value);
00070         list << RealTime::frame2RealTime(duration, sampleRate).toString().c_str();
00071         list << QString("%1").arg(level);
00072         if (label != "") list << label;
00073         return list.join(delimiter);
00074     }
00075 
00076     struct Comparator {
00077         bool operator()(const Note &p1,
00078                         const Note &p2) const {
00079             if (p1.frame != p2.frame) return p1.frame < p2.frame;
00080             if (p1.value != p2.value) return p1.value < p2.value;
00081             if (p1.duration != p2.duration) return p1.duration < p2.duration;
00082             if (p1.level != p2.level) return p1.level < p2.level;
00083             return p1.label < p2.label;
00084         }
00085     };
00086     
00087     struct OrderComparator {
00088         bool operator()(const Note &p1,
00089                         const Note &p2) const {
00090             return p1.frame < p2.frame;
00091         }
00092     };
00093 };
00094 
00095 
00096 class NoteModel : public IntervalModel<Note>, public NoteExportable
00097 {
00098     Q_OBJECT
00099     
00100 public:
00101     NoteModel(int sampleRate, int resolution,
00102               bool notifyOnAdd = true) :
00103         IntervalModel<Note>(sampleRate, resolution, notifyOnAdd),
00104         m_valueQuantization(0)
00105     {
00106         PlayParameterRepository::getInstance()->addPlayable(this);
00107     }
00108 
00109     NoteModel(int sampleRate, int resolution,
00110               float valueMinimum, float valueMaximum,
00111               bool notifyOnAdd = true) :
00112         IntervalModel<Note>(sampleRate, resolution,
00113                             valueMinimum, valueMaximum,
00114                             notifyOnAdd),
00115         m_valueQuantization(0)
00116     {
00117         PlayParameterRepository::getInstance()->addPlayable(this);
00118     }
00119 
00120     virtual ~NoteModel()
00121     {
00122         PlayParameterRepository::getInstance()->removePlayable(this);
00123     }
00124 
00125     float getValueQuantization() const { return m_valueQuantization; }
00126     void setValueQuantization(float q) { m_valueQuantization = q; }
00127 
00128     QString getTypeName() const { return tr("Note"); }
00129 
00130     virtual bool canPlay() const { return true; }
00131 
00132     virtual QString getDefaultPlayClipId() const
00133     {
00134         return "elecpiano";
00135     }
00136 
00137     virtual void toXml(QTextStream &out,
00138                        QString indent = "",
00139                        QString extraAttributes = "") const
00140     {
00141         std::cerr << "NoteModel::toXml: extraAttributes = \"" 
00142                   << extraAttributes.toStdString() << std::endl;
00143 
00144         IntervalModel<Note>::toXml
00145             (out,
00146              indent,
00147              QString("%1 subtype=\"note\" valueQuantization=\"%2\"")
00148              .arg(extraAttributes).arg(m_valueQuantization));
00149     }
00150 
00155     virtual int getColumnCount() const
00156     {
00157         return 6;
00158     }
00159 
00160     virtual QString getHeading(int column) const
00161     {
00162         switch (column) {
00163         case 0: return tr("Time");
00164         case 1: return tr("Frame");
00165         case 2: return tr("Pitch");
00166         case 3: return tr("Duration");
00167         case 4: return tr("Level");
00168         case 5: return tr("Label");
00169         default: return tr("Unknown");
00170         }
00171     }
00172 
00173     virtual QVariant getData(int row, int column, int role) const
00174     {
00175         if (column < 4) {
00176             return IntervalModel<Note>::getData(row, column, role);
00177         }
00178 
00179         PointListConstIterator i = getPointListIteratorForRow(row);
00180         if (i == m_points.end()) return QVariant();
00181 
00182         switch (column) {
00183         case 4: return i->level;
00184         case 5: return i->label;
00185         default: return QVariant();
00186         }
00187     }
00188 
00189     virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
00190     {
00191         if (column < 4) {
00192             return IntervalModel<Note>::getSetDataCommand
00193                 (row, column, value, role);
00194         }
00195 
00196         if (role != Qt::EditRole) return 0;
00197         PointListConstIterator i = getPointListIteratorForRow(row);
00198         if (i == m_points.end()) return 0;
00199         EditCommand *command = new EditCommand(this, tr("Edit Data"));
00200 
00201         Point point(*i);
00202         command->deletePoint(point);
00203 
00204         switch (column) {
00205         case 4: point.level = value.toDouble(); break;
00206         case 5: point.label = value.toString(); break;
00207         }
00208 
00209         command->addPoint(point);
00210         return command->finish();
00211     }
00212 
00213     virtual SortType getSortType(int column) const
00214     {
00215         if (column == 5) return SortAlphabetical;
00216         return SortNumeric;
00217     }
00218 
00223     NoteList getNotes() const {
00224         return getNotesWithin(getStartFrame(), getEndFrame());
00225     }
00226 
00227     NoteList getNotesWithin(int startFrame, int endFrame) const {
00228         
00229         PointList points = getPoints(startFrame, endFrame);
00230         NoteList notes;
00231 
00232         for (PointList::iterator pli =
00233                  points.begin(); pli != points.end(); ++pli) {
00234 
00235             int duration = pli->duration;
00236             if (duration == 0 || duration == 1) {
00237                 duration = getSampleRate() / 20;
00238             }
00239 
00240             int pitch = lrintf(pli->value);
00241             
00242             int velocity = 100;
00243             if (pli->level > 0.f && pli->level <= 1.f) {
00244                 velocity = lrintf(pli->level * 127);
00245             }
00246 
00247             NoteData note(pli->frame, duration, pitch, velocity);
00248 
00249             if (getScaleUnits() == "Hz") {
00250                 note.frequency = pli->value;
00251                 note.midiPitch = Pitch::getPitchForFrequency(note.frequency);
00252                 note.isMidiPitchQuantized = false;
00253             }
00254         
00255             notes.push_back(note);
00256         }
00257         
00258         return notes;
00259     }
00260 
00261 protected:
00262     float m_valueQuantization;
00263 };
00264 
00265 #endif