Mercurial > hg > svcore
comparison transform/RealTimeEffectModelTransformer.cpp @ 388:370aa9714ef5
* Move plugin/transform to plain transform.  This way transform can depend on
  model and GUI classes, but plugin doesn't have to.
| author | Chris Cannam | 
|---|---|
| date | Wed, 12 Mar 2008 18:02:17 +0000 | 
| parents | plugin/transform/RealTimeEffectModelTransformer.cpp@876a79afd376 | 
| children | c8955c486340 | 
   comparison
  equal
  deleted
  inserted
  replaced
| 387:7aa1de571880 | 388:370aa9714ef5 | 
|---|---|
| 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
| 2 | |
| 3 /* | |
| 4 Sonic Visualiser | |
| 5 An audio file viewer and annotation editor. | |
| 6 Centre for Digital Music, Queen Mary, University of London. | |
| 7 This file copyright 2006 Chris Cannam and QMUL. | |
| 8 | |
| 9 This program is free software; you can redistribute it and/or | |
| 10 modify it under the terms of the GNU General Public License as | |
| 11 published by the Free Software Foundation; either version 2 of the | |
| 12 License, or (at your option) any later version. See the file | |
| 13 COPYING included with this distribution for more information. | |
| 14 */ | |
| 15 | |
| 16 #include "RealTimeEffectModelTransformer.h" | |
| 17 | |
| 18 #include "plugin/RealTimePluginFactory.h" | |
| 19 #include "plugin/RealTimePluginInstance.h" | |
| 20 #include "plugin/PluginXml.h" | |
| 21 | |
| 22 #include "data/model/Model.h" | |
| 23 #include "data/model/SparseTimeValueModel.h" | |
| 24 #include "data/model/DenseTimeValueModel.h" | |
| 25 #include "data/model/WritableWaveFileModel.h" | |
| 26 #include "data/model/WaveFileModel.h" | |
| 27 | |
| 28 #include "TransformFactory.h" | |
| 29 | |
| 30 #include <iostream> | |
| 31 | |
| 32 RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Input in, | |
| 33 const Transform &transform) : | |
| 34 ModelTransformer(in, transform), | |
| 35 m_plugin(0) | |
| 36 { | |
| 37 m_units = TransformFactory::getInstance()->getTransformUnits | |
| 38 (transform.getIdentifier()); | |
| 39 m_outputNo = | |
| 40 (transform.getOutput() == "A") ? -1 : transform.getOutput().toInt(); | |
| 41 | |
| 42 QString pluginId = transform.getPluginIdentifier(); | |
| 43 | |
| 44 if (!m_transform.getBlockSize()) m_transform.setBlockSize(1024); | |
| 45 | |
| 46 // std::cerr << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId.toStdString() << ", output " << output << std::endl; | |
| 47 | |
| 48 RealTimePluginFactory *factory = | |
| 49 RealTimePluginFactory::instanceFor(pluginId); | |
| 50 | |
| 51 if (!factory) { | |
| 52 std::cerr << "RealTimeEffectModelTransformer: No factory available for plugin id \"" | |
| 53 << pluginId.toStdString() << "\"" << std::endl; | |
| 54 return; | |
| 55 } | |
| 56 | |
| 57 DenseTimeValueModel *input = getConformingInput(); | |
| 58 if (!input) return; | |
| 59 | |
| 60 m_plugin = factory->instantiatePlugin(pluginId, 0, 0, | |
| 61 input->getSampleRate(), | |
| 62 m_transform.getBlockSize(), | |
| 63 input->getChannelCount()); | |
| 64 | |
| 65 if (!m_plugin) { | |
| 66 std::cerr << "RealTimeEffectModelTransformer: Failed to instantiate plugin \"" | |
| 67 << pluginId.toStdString() << "\"" << std::endl; | |
| 68 return; | |
| 69 } | |
| 70 | |
| 71 TransformFactory::getInstance()->setPluginParameters(m_transform, m_plugin); | |
| 72 | |
| 73 if (m_outputNo >= 0 && | |
| 74 m_outputNo >= int(m_plugin->getControlOutputCount())) { | |
| 75 std::cerr << "RealTimeEffectModelTransformer: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl; | |
| 76 return; | |
| 77 } | |
| 78 | |
| 79 if (m_outputNo == -1) { | |
| 80 | |
| 81 size_t outputChannels = m_plugin->getAudioOutputCount(); | |
| 82 if (outputChannels > input->getChannelCount()) { | |
| 83 outputChannels = input->getChannelCount(); | |
| 84 } | |
| 85 | |
| 86 WritableWaveFileModel *model = new WritableWaveFileModel | |
| 87 (input->getSampleRate(), outputChannels); | |
| 88 | |
| 89 m_output = model; | |
| 90 | |
| 91 } else { | |
| 92 | |
| 93 SparseTimeValueModel *model = new SparseTimeValueModel | |
| 94 (input->getSampleRate(), m_transform.getBlockSize(), 0.0, 0.0, false); | |
| 95 | |
| 96 if (m_units != "") model->setScaleUnits(m_units); | |
| 97 | |
| 98 m_output = model; | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 RealTimeEffectModelTransformer::~RealTimeEffectModelTransformer() | |
| 103 { | |
| 104 delete m_plugin; | |
| 105 } | |
| 106 | |
| 107 DenseTimeValueModel * | |
| 108 RealTimeEffectModelTransformer::getConformingInput() | |
| 109 { | |
| 110 DenseTimeValueModel *dtvm = | |
| 111 dynamic_cast<DenseTimeValueModel *>(getInputModel()); | |
| 112 if (!dtvm) { | |
| 113 std::cerr << "RealTimeEffectModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl; | |
| 114 } | |
| 115 return dtvm; | |
| 116 } | |
| 117 | |
| 118 void | |
| 119 RealTimeEffectModelTransformer::run() | |
| 120 { | |
| 121 DenseTimeValueModel *input = getConformingInput(); | |
| 122 if (!input) return; | |
| 123 | |
| 124 while (!input->isReady()) { | |
| 125 if (dynamic_cast<WaveFileModel *>(input)) break; // no need to wait | |
| 126 std::cerr << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << std::endl; | |
| 127 sleep(1); | |
| 128 } | |
| 129 | |
| 130 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_output); | |
| 131 WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_output); | |
| 132 if (!stvm && !wwfm) return; | |
| 133 | |
| 134 if (stvm && (m_outputNo >= int(m_plugin->getControlOutputCount()))) return; | |
| 135 | |
| 136 size_t sampleRate = input->getSampleRate(); | |
| 137 size_t channelCount = input->getChannelCount(); | |
| 138 if (!wwfm && m_input.getChannel() != -1) channelCount = 1; | |
| 139 | |
| 140 long blockSize = m_plugin->getBufferSize(); | |
| 141 | |
| 142 float **inbufs = m_plugin->getAudioInputBuffers(); | |
| 143 | |
| 144 long startFrame = m_input.getModel()->getStartFrame(); | |
| 145 long endFrame = m_input.getModel()->getEndFrame(); | |
| 146 | |
| 147 RealTime contextStartRT = m_transform.getStartTime(); | |
| 148 RealTime contextDurationRT = m_transform.getDuration(); | |
| 149 | |
| 150 long contextStart = | |
| 151 RealTime::realTime2Frame(contextStartRT, sampleRate); | |
| 152 | |
| 153 long contextDuration = | |
| 154 RealTime::realTime2Frame(contextDurationRT, sampleRate); | |
| 155 | |
| 156 if (contextStart == 0 || contextStart < startFrame) { | |
| 157 contextStart = startFrame; | |
| 158 } | |
| 159 | |
| 160 if (contextDuration == 0) { | |
| 161 contextDuration = endFrame - contextStart; | |
| 162 } | |
| 163 if (contextStart + contextDuration > endFrame) { | |
| 164 contextDuration = endFrame - contextStart; | |
| 165 } | |
| 166 | |
| 167 wwfm->setStartFrame(contextStart); | |
| 168 | |
| 169 long blockFrame = contextStart; | |
| 170 | |
| 171 long prevCompletion = 0; | |
| 172 | |
| 173 long latency = m_plugin->getLatency(); | |
| 174 | |
| 175 while (blockFrame < contextStart + contextDuration + latency && | |
| 176 !m_abandoned) { | |
| 177 | |
| 178 long completion = | |
| 179 (((blockFrame - contextStart) / blockSize) * 99) / | |
| 180 ((contextDuration) / blockSize); | |
| 181 | |
| 182 long got = 0; | |
| 183 | |
| 184 if (channelCount == 1) { | |
| 185 if (inbufs && inbufs[0]) { | |
| 186 got = input->getData | |
| 187 (m_input.getChannel(), blockFrame, blockSize, inbufs[0]); | |
| 188 while (got < blockSize) { | |
| 189 inbufs[0][got++] = 0.0; | |
| 190 } | |
| 191 } | |
| 192 for (size_t ch = 1; ch < m_plugin->getAudioInputCount(); ++ch) { | |
| 193 for (long i = 0; i < blockSize; ++i) { | |
| 194 inbufs[ch][i] = inbufs[0][i]; | |
| 195 } | |
| 196 } | |
| 197 } else { | |
| 198 got = input->getData(0, channelCount - 1, | |
| 199 blockFrame, blockSize, | |
| 200 inbufs); | |
| 201 while (got < blockSize) { | |
| 202 for (size_t ch = 0; ch < channelCount; ++ch) { | |
| 203 inbufs[ch][got] = 0.0; | |
| 204 } | |
| 205 ++got; | |
| 206 } | |
| 207 for (size_t ch = channelCount; ch < m_plugin->getAudioInputCount(); ++ch) { | |
| 208 for (long i = 0; i < blockSize; ++i) { | |
| 209 inbufs[ch][i] = inbufs[ch % channelCount][i]; | |
| 210 } | |
| 211 } | |
| 212 } | |
| 213 | |
| 214 /* | |
| 215 std::cerr << "Input for plugin: " << m_plugin->getAudioInputCount() << " channels "<< std::endl; | |
| 216 | |
| 217 for (size_t ch = 0; ch < m_plugin->getAudioInputCount(); ++ch) { | |
| 218 std::cerr << "Input channel " << ch << std::endl; | |
| 219 for (size_t i = 0; i < 100; ++i) { | |
| 220 std::cerr << inbufs[ch][i] << " "; | |
| 221 if (isnan(inbufs[ch][i])) { | |
| 222 std::cerr << "\n\nWARNING: NaN in audio input" << std::endl; | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 */ | |
| 227 | |
| 228 m_plugin->run(Vamp::RealTime::frame2RealTime(blockFrame, sampleRate)); | |
| 229 | |
| 230 if (stvm) { | |
| 231 | |
| 232 float value = m_plugin->getControlOutputValue(m_outputNo); | |
| 233 | |
| 234 long pointFrame = blockFrame; | |
| 235 if (pointFrame > latency) pointFrame -= latency; | |
| 236 else pointFrame = 0; | |
| 237 | |
| 238 stvm->addPoint(SparseTimeValueModel::Point | |
| 239 (pointFrame, value, "")); | |
| 240 | |
| 241 } else if (wwfm) { | |
| 242 | |
| 243 float **outbufs = m_plugin->getAudioOutputBuffers(); | |
| 244 | |
| 245 if (outbufs) { | |
| 246 | |
| 247 if (blockFrame >= latency) { | |
| 248 long writeSize = std::min | |
| 249 (blockSize, | |
| 250 contextStart + contextDuration + latency - blockFrame); | |
| 251 wwfm->addSamples(outbufs, writeSize); | |
| 252 } else if (blockFrame + blockSize >= latency) { | |
| 253 long offset = latency - blockFrame; | |
| 254 long count = blockSize - offset; | |
| 255 float **tmp = new float *[channelCount]; | |
| 256 for (size_t c = 0; c < channelCount; ++c) { | |
| 257 tmp[c] = outbufs[c] + offset; | |
| 258 } | |
| 259 wwfm->addSamples(tmp, count); | |
| 260 delete[] tmp; | |
| 261 } | |
| 262 } | |
| 263 } | |
| 264 | |
| 265 if (blockFrame == contextStart || completion > prevCompletion) { | |
| 266 if (stvm) stvm->setCompletion(completion); | |
| 267 if (wwfm) wwfm->setCompletion(completion); | |
| 268 prevCompletion = completion; | |
| 269 } | |
| 270 | |
| 271 blockFrame += blockSize; | |
| 272 } | |
| 273 | |
| 274 if (m_abandoned) return; | |
| 275 | |
| 276 if (stvm) stvm->setCompletion(100); | |
| 277 if (wwfm) wwfm->setCompletion(100); | |
| 278 } | |
| 279 | 
