| Chris@107 | 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */ | 
| Chris@107 | 2 | 
| Chris@107 | 3 /* | 
| Chris@107 | 4     Sonic Annotator | 
| Chris@107 | 5     A utility for batch feature extraction from audio files. | 
| Chris@107 | 6     Mark Levy, Chris Sutton and Chris Cannam, Queen Mary, University of London. | 
| Chris@107 | 7     Copyright 2007-2014 QMUL. | 
| Chris@107 | 8 | 
| Chris@107 | 9     This program is free software; you can redistribute it and/or | 
| Chris@107 | 10     modify it under the terms of the GNU General Public License as | 
| Chris@107 | 11     published by the Free Software Foundation; either version 2 of the | 
| Chris@107 | 12     License, or (at your option) any later version.  See the file | 
| Chris@107 | 13     COPYING included with this distribution for more information. | 
| Chris@107 | 14 */ | 
| Chris@107 | 15 | 
| Chris@107 | 16 #include "MultiplexedReader.h" | 
| Chris@107 | 17 | 
| Chris@107 | 18 MultiplexedReader::MultiplexedReader(QList<AudioFileReader *> readers) : | 
| Chris@107 | 19     m_readers(readers) | 
| Chris@107 | 20 { | 
| Chris@107 | 21     m_channelCount = readers.size(); | 
| Chris@107 | 22     m_sampleRate = readers[0]->getSampleRate(); | 
| Chris@107 | 23 | 
| Chris@263 | 24     SVDEBUG << "MultiplexedReader: channel count: " << m_channelCount | 
| Chris@263 | 25             << " (i.e. " << m_channelCount << " reader(s) to multiplex)" << endl; | 
| Chris@263 | 26     SVDEBUG << "MultiplexedReader: sample rate from first reader: " | 
| Chris@263 | 27             << m_sampleRate << endl; | 
| Chris@263 | 28 | 
| Chris@107 | 29     m_frameCount = 0; | 
| Chris@107 | 30     m_quicklySeekable = true; | 
| Chris@107 | 31 | 
| Chris@107 | 32     foreach (AudioFileReader *r, m_readers) { | 
| Chris@107 | 33 	if (!r->isOK()) { | 
| Chris@107 | 34 	    m_channelCount = 0; | 
| Chris@107 | 35 	    m_error = r->getError(); | 
| Chris@185 | 36         } else if (r->getSampleRate() != m_sampleRate) { | 
| Chris@185 | 37             m_channelCount = 0; | 
| Chris@185 | 38             m_error = "Readers provided to MultiplexedReader must have the same sample rate"; | 
| Chris@107 | 39 	} else { | 
| Chris@107 | 40 	    if (r->getFrameCount() > m_frameCount) { | 
| Chris@107 | 41 		m_frameCount = r->getFrameCount(); | 
| Chris@107 | 42 	    } | 
| Chris@107 | 43 	    if (!r->isQuicklySeekable()) { | 
| Chris@107 | 44 		m_quicklySeekable = false; | 
| Chris@107 | 45 	    } | 
| Chris@107 | 46 	} | 
| Chris@107 | 47     } | 
| Chris@107 | 48 } | 
| Chris@107 | 49 | 
| Chris@107 | 50 MultiplexedReader::~MultiplexedReader() | 
| Chris@107 | 51 { | 
| Chris@107 | 52     foreach (AudioFileReader *r, m_readers) { | 
| Chris@107 | 53 	delete r; | 
| Chris@107 | 54     } | 
| Chris@107 | 55 } | 
| Chris@107 | 56 | 
| Chris@258 | 57 std::vector<float> | 
| Chris@195 | 58 MultiplexedReader::getInterleavedFrames(sv_frame_t start, sv_frame_t frameCount) const | 
| Chris@107 | 59 { | 
| Chris@114 | 60     int out_chans = m_readers.size(); | 
| Chris@107 | 61 | 
| Chris@114 | 62     // Allocate and zero | 
| Chris@258 | 63     std::vector<float> block(frameCount * out_chans, 0.f); | 
| Chris@107 | 64 | 
| Chris@114 | 65     for (int out_chan = 0; out_chan < out_chans; ++out_chan) { | 
| Chris@107 | 66 | 
| Chris@114 | 67 	AudioFileReader *reader = m_readers[out_chan]; | 
| Chris@258 | 68 	auto readerBlock = reader->getInterleavedFrames(start, frameCount); | 
| Chris@107 | 69 | 
| Chris@114 | 70 	int in_chans = reader->getChannelCount(); | 
| Chris@107 | 71 | 
| Chris@114 | 72 	for (int frame = 0; frame < frameCount; ++frame) { | 
| Chris@114 | 73 | 
| Chris@114 | 74             int out_index = frame * out_chans + out_chan; | 
| Chris@114 | 75 | 
| Chris@114 | 76 	    for (int in_chan = 0; in_chan < in_chans; ++in_chan) { | 
| Chris@114 | 77                 int in_index = frame * in_chans + in_chan; | 
| Chris@114 | 78                 if (in_index >= (int)readerBlock.size()) break; | 
| Chris@114 | 79 		block[out_index] += readerBlock[in_index]; | 
| Chris@107 | 80 	    } | 
| Chris@114 | 81 | 
| Chris@114 | 82             if (in_chans > 1) { | 
| Chris@114 | 83                 block[out_index] /= float(in_chans); | 
| Chris@114 | 84             } | 
| Chris@107 | 85 	} | 
| Chris@107 | 86     } | 
| Chris@195 | 87 | 
| Chris@195 | 88     return block; | 
| Chris@107 | 89 } | 
| Chris@107 | 90 | 
| Chris@107 | 91 int | 
| Chris@107 | 92 MultiplexedReader::getDecodeCompletion() const | 
| Chris@107 | 93 { | 
| Chris@107 | 94     int completion = 100; | 
| Chris@107 | 95     foreach (AudioFileReader *r, m_readers) { | 
| Chris@107 | 96 	int c = r->getDecodeCompletion(); | 
| Chris@107 | 97 	if (c < 100) { | 
| Chris@107 | 98 	    completion = c; | 
| Chris@107 | 99 	} | 
| Chris@107 | 100     } | 
| Chris@107 | 101     return completion; | 
| Chris@107 | 102 } | 
| Chris@107 | 103 | 
| Chris@107 | 104 bool | 
| Chris@107 | 105 MultiplexedReader::isUpdating() const | 
| Chris@107 | 106 { | 
| Chris@107 | 107     foreach (AudioFileReader *r, m_readers) { | 
| Chris@107 | 108 	if (r->isUpdating()) return true; | 
| Chris@107 | 109     } | 
| Chris@107 | 110     return false; | 
| Chris@107 | 111 } | 
| Chris@107 | 112 | 
| Chris@107 | 113 | 
| Chris@107 | 114 |