1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
/***************************************************************************
Writer.cpp - base class for writers, providing a C++ stream interface
-------------------
begin : Sun Aug 23 2009
copyright : (C) 2009 by Thomas Eschenbacher
email : Thomas Eschenbacher <thomas.eschenbacher@gmx.de>
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "config.h"
#include <QObject>
#include "libkwave/SampleReader.h"
#include "libkwave/Utils.h"
#include "libkwave/Writer.h"
#include "libkwave/memcpy.h"
/** size of m_buffer in samples */
#define BUFFER_SIZE (1024 * 1024)
/** minimum block size used for direct block i/o */
#define MIN_DIRECT_IO_BLOCK_SIZE (BUFFER_SIZE / 2)
//***************************************************************************
Kwave::Writer::Writer()
:Kwave::SampleSink(nullptr),
m_first(0), m_last(0), m_mode(Kwave::Insert), m_position(0),
m_buffer(BUFFER_SIZE), m_buffer_size(BUFFER_SIZE), m_buffer_used(0)
{
}
//***************************************************************************
Kwave::Writer::Writer(Kwave::InsertMode mode,
sample_index_t left, sample_index_t right)
:Kwave::SampleSink(nullptr),
m_first(left), m_last(right), m_mode(mode), m_position(left),
m_buffer(BUFFER_SIZE), m_buffer_size(BUFFER_SIZE), m_buffer_used(0)
{
}
//***************************************************************************
Kwave::Writer::~Writer()
{
// If this assert gets hit, you deleted a writer without calling
// flush() before. Flushing in the destructor is problematic and
// might be too late when the derived classes' destructor was
// already done and signal/slot connections were already released!
Q_ASSERT(!m_buffer_used);
if (m_buffer_used) qWarning("Writer was not flushed!?");
Q_ASSERT((m_mode != Kwave::Overwrite) || (m_position <= m_last + 1));
// inform others that we proceeded
emit sigSamplesWritten(m_position - m_first);
}
//***************************************************************************
Kwave::Writer &Kwave::Writer::operator << (const Kwave::SampleArray &samples)
{
unsigned int count = samples.size();
if ( (m_buffer_used || (count < MIN_DIRECT_IO_BLOCK_SIZE)) &&
(m_buffer_used + count <= m_buffer_size) )
{
// append to the internal buffer if it is already in use
// and if there is still some room,
// or if the buffer so small that it would make too much overhead
// to process it by block operation
MEMCPY(&(m_buffer[m_buffer_used]), &(samples[0]),
count * sizeof(sample_t));
m_buffer_used += count;
if (m_buffer_used >= m_buffer_size) flush();
} else {
// first flush the single-sample buffer before doing block operation
if (m_buffer_used) flush();
// now flush the block that we received as parameter (pass-through)
write(samples, count);
Q_ASSERT(!count);
}
return *this;
}
//***************************************************************************
Kwave::Writer &Kwave::Writer::operator << (const sample_t &sample)
{
m_buffer[m_buffer_used++] = sample;
if (m_buffer_used >= m_buffer_size) flush();
return *this;
}
//***************************************************************************
Kwave::Writer &Kwave::Writer::operator << (Kwave::SampleReader &reader)
{
if (m_buffer_used) flush();
// transfer data, using our internal buffer
unsigned int buflen = m_buffer_size;
while (!reader.eof() && !eof()) {
// overwrite mode -> clip at right border
if (m_mode == Kwave::Overwrite) {
if (m_position + buflen - 1 > m_last)
buflen = Kwave::toUint(m_last - m_position + 1);
}
m_buffer_used = reader.read(m_buffer, 0, buflen);
Q_ASSERT(m_buffer_used);
if (!m_buffer_used) break;
if (!flush()) return *this; // out of memory
}
// pad the rest with zeroes
if (m_mode == Kwave::Overwrite) {
Q_ASSERT(m_position <= m_last + 1);
while (m_buffer_used + m_position <= m_last) {
*this << static_cast<sample_t>(0);
m_position++;
}
Q_ASSERT(m_position <= m_last + 1);
}
return *this;
}
//***************************************************************************
bool Kwave::Writer::eof() const
{
return (m_mode == Kwave::Overwrite) ? (m_position > m_last) : false;
}
//***************************************************************************
Kwave::Writer &flush(Kwave::Writer &s)
{
s.flush();
return s;
}
//***************************************************************************
void Kwave::Writer::input(Kwave::SampleArray data)
{
if (data.size()) (*this) << data;
}
//***************************************************************************
//***************************************************************************
#include "moc_Writer.cpp"
|