annotate runner/MIDIFeatureWriter.cpp @ 141:d7a91e07ca57 midi

Flesh out MIDI writer
author Chris Cannam
date Mon, 13 Oct 2014 13:37:31 +0100
parents 9b94545a7fdc
children b3d73c08b6ce
rev   line source
Chris@137 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@137 2
Chris@137 3 /*
Chris@137 4 Sonic Annotator
Chris@137 5 A utility for batch feature extraction from audio files.
Chris@137 6 Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London.
Chris@137 7 Copyright 2007-2014 QMUL.
Chris@137 8
Chris@137 9 This program is free software; you can redistribute it and/or
Chris@137 10 modify it under the terms of the GNU General Public License as
Chris@137 11 published by the Free Software Foundation; either version 2 of the
Chris@137 12 License, or (at your option) any later version. See the file
Chris@137 13 COPYING included with this distribution for more information.
Chris@137 14 */
Chris@137 15
Chris@137 16 #include "MIDIFeatureWriter.h"
Chris@137 17
Chris@137 18 using namespace std;
Chris@137 19 using Vamp::Plugin;
Chris@137 20 using Vamp::PluginBase;
Chris@137 21
Chris@137 22 #include "base/Exceptions.h"
Chris@137 23 #include "data/fileio/MIDIFileWriter.h"
Chris@137 24
Chris@137 25 MIDIFeatureWriter::MIDIFeatureWriter() :
Chris@137 26 FileFeatureWriter(SupportOneFilePerTrackTransform |
Chris@137 27 SupportOneFilePerTrack |
Chris@137 28 SupportOneFileTotal,
Chris@137 29 "mid")
Chris@137 30 {
Chris@137 31 }
Chris@137 32
Chris@137 33 MIDIFeatureWriter::~MIDIFeatureWriter()
Chris@137 34 {
Chris@137 35 }
Chris@137 36
Chris@137 37 MIDIFeatureWriter::ParameterList
Chris@137 38 MIDIFeatureWriter::getSupportedParameters() const
Chris@137 39 {
Chris@137 40 ParameterList pl = FileFeatureWriter::getSupportedParameters();
Chris@137 41 return pl;
Chris@137 42 }
Chris@137 43
Chris@137 44 void
Chris@137 45 MIDIFeatureWriter::setParameters(map<string, string> &params)
Chris@137 46 {
Chris@137 47 FileFeatureWriter::setParameters(params);
Chris@137 48 }
Chris@137 49
Chris@137 50 void
Chris@137 51 MIDIFeatureWriter::setTrackMetadata(QString, TrackMetadata)
Chris@137 52 {
Chris@137 53 cerr << "MIDIFeatureWriter::setTrackMetadata: not supported (yet?)" << endl;
Chris@137 54 }
Chris@137 55
Chris@137 56 void
Chris@137 57 MIDIFeatureWriter::write(QString trackId,
Chris@137 58 const Transform &transform,
Chris@137 59 const Plugin::OutputDescriptor& output,
Chris@137 60 const Plugin::FeatureList& features,
Chris@141 61 std::string /* summaryType */)
Chris@137 62 {
Chris@140 63 QString transformId = transform.getIdentifier();
Chris@140 64
Chris@140 65 QString filename = getOutputFilename(trackId, transformId);
Chris@137 66 if (filename == "") {
Chris@140 67 throw FailedToOpenOutputStream(trackId, transformId);
Chris@137 68 }
Chris@137 69
Chris@141 70 int sampleRate = transform.getSampleRate();
Chris@141 71
Chris@140 72 if (m_rates.find(filename) == m_rates.end()) {
Chris@140 73 m_rates[filename] = sampleRate;
Chris@140 74 }
Chris@140 75
Chris@140 76 if (m_fileTransforms[filename].find(transformId) ==
Chris@140 77 m_fileTransforms[filename].end()) {
Chris@140 78
Chris@140 79 // This transform is new to the file, give it a channel number
Chris@140 80
Chris@140 81 int channel = m_nextChannels[filename];
Chris@140 82 m_nextChannels[filename] = channel + 1;
Chris@140 83
Chris@140 84 m_fileTransforms[filename].insert(transformId);
Chris@140 85 m_channels[transformId] = channel;
Chris@140 86 }
Chris@140 87
Chris@140 88 NoteList notes = m_notes[filename];
Chris@140 89
Chris@141 90 bool freq = (output.unit == "Hz" ||
Chris@141 91 output.unit == "hz" ||
Chris@141 92 output.unit == "HZ");
Chris@141 93
Chris@141 94 for (int i = 0; i < (int)features.size(); ++i) {
Chris@141 95
Chris@141 96 const Plugin::Feature &feature(features[i]);
Chris@141 97
Chris@141 98 Vamp::RealTime timestamp = feature.timestamp;
Chris@141 99 int frame = Vamp::RealTime::realTime2Frame(timestamp, sampleRate);
Chris@141 100
Chris@141 101 int duration = 1;
Chris@141 102 if (feature.hasDuration) {
Chris@141 103 duration = Vamp::RealTime::realTime2Frame(feature.duration, sampleRate);
Chris@141 104 }
Chris@141 105
Chris@141 106 int pitch = 60;
Chris@141 107 if (feature.values.size() > 0) {
Chris@141 108 float pval = feature.values[0];
Chris@141 109 if (freq) {
Chris@141 110 pitch = Pitch::getPitchForFrequency(pval);
Chris@141 111 } else {
Chris@141 112 pitch = int(pval + 0.5);
Chris@141 113 }
Chris@141 114 }
Chris@141 115
Chris@141 116 int velocity = 100;
Chris@141 117 if (feature.values.size() > 1) {
Chris@141 118 float vval = feature.values[1];
Chris@141 119 if (vval < 128) {
Chris@141 120 velocity = int(vval + 0.5);
Chris@141 121 }
Chris@141 122 }
Chris@141 123
Chris@141 124 NoteData note(frame, duration, pitch, velocity);
Chris@141 125
Chris@141 126 note.channel = m_channels[transformId];
Chris@141 127
Chris@141 128 notes.push_back(note);
Chris@141 129 }
Chris@140 130
Chris@140 131 m_notes[filename] = notes;
Chris@137 132 }
Chris@137 133
Chris@137 134 void
Chris@137 135 MIDIFeatureWriter::finish()
Chris@137 136 {
Chris@137 137 for (NoteMap::const_iterator i = m_notes.begin(); i != m_notes.end(); ++i) {
Chris@137 138
Chris@137 139 QString filename = i->first;
Chris@137 140 NoteList notes = i->second;
Chris@137 141 float rate = m_rates[filename];
Chris@137 142
Chris@137 143 TrivialNoteExportable exportable(notes);
Chris@137 144
Chris@137 145 {
Chris@137 146 MIDIFileWriter writer(filename, &exportable, rate);
Chris@137 147 if (!writer.isOK()) {
Chris@137 148 cerr << "ERROR: Failed to create MIDI writer: "
Chris@137 149 << writer.getError() << endl;
Chris@137 150 throw FileOperationFailed(filename, "create MIDI writer");
Chris@137 151 }
Chris@137 152 writer.write();
Chris@137 153 }
Chris@137 154 }
Chris@137 155 }
Chris@137 156