23 #include <KLocalizedString> 71 unsigned int frame_size)
74 quint32 correct_size = length * frame_size;
79 qWarning(
"WARNING: libaudiofile might have produced a broken header!");
86 memset(chunk_name, 0x00,
sizeof(chunk_name));
87 dst.read(&chunk_name[0], 4);
88 if (strncmp(
"data", chunk_name,
sizeof(chunk_name))) {
89 qWarning(
"WARNING: unexpected wav header format, check disabled");
96 dst.read(reinterpret_cast<char *>(&data_size), 4);
97 data_size = qFromLittleEndian<quint32>(data_size);
98 if (data_size == length * frame_size) {
103 qWarning(
"WARNING: libaudiofile wrote a wrong 'data' chunk size!");
104 qWarning(
" current=%u, correct=%u", data_size, correct_size);
108 data_size = qToLittleEndian<quint32>(correct_size);
109 dst.write(reinterpret_cast<char *>(&data_size), 4);
113 quint32 riff_size =
static_cast<quint32
>(dst.size()) - 4 - 4;
114 riff_size = qToLittleEndian<quint32>(riff_size);
115 dst.write(reinterpret_cast<char *>(&riff_size), 4);
123 QMap<Kwave::FileProperty, QVariant> properties(info.
properties());
124 QMap<QByteArray, QByteArray> info_chunks;
125 unsigned int info_size = 0;
127 for (QMap<Kwave::FileProperty, QVariant>::Iterator it = properties.begin();
128 it != properties.end(); ++it)
134 if (info_chunks.contains(chunk_id))
continue;
136 QByteArray value = QVariant(properties[property]).toString().toUtf8();
137 info_chunks.insert(chunk_id, value);
138 info_size += 4 + 4 + value.length();
139 if (value.length() & 0x01) info_size++;
143 if (!info_chunks.isEmpty()) {
147 info_size += 4 + 4 + 4;
149 dst.read(reinterpret_cast<char *>(&size), 4);
150 size = qToLittleEndian<quint32>(
151 qFromLittleEndian<quint32>(size) + info_size);
153 dst.write(reinterpret_cast<char *>(&size), 4);
156 dst.seek(dst.size());
157 if (dst.pos() & 1) dst.write(
"\000", 1);
158 dst.write(
"LIST", 4);
159 size = qToLittleEndian<quint32>(info_size - 8);
160 dst.write(reinterpret_cast<char *>(&size), 4);
161 dst.write(
"INFO", 4);
164 for (QMap<QByteArray, QByteArray>::Iterator it = info_chunks.begin();
165 it != info_chunks.end(); ++it)
167 QByteArray
name = it.key();
168 QByteArray value = it.value();
170 dst.write(name.data(), 4);
171 size = value.length();
172 if (size & 0x01) size++;
173 size = qToLittleEndian<quint32>(size);
174 dst.write(reinterpret_cast<char *>(&size), 4);
175 dst.write(value.data(), value.length());
176 if (value.length() & 0x01) {
188 const unsigned int labels_count = labels.count();
189 quint32 size, additional_size = 0, index, data;
192 if (!labels_count)
return;
196 const unsigned int size_of_cue_list =
198 labels_count * (6 * 4);
201 unsigned int size_of_labels = 0;
203 if (label.
isNull())
continue;
204 unsigned int name_len = label.
name().toUtf8().size();
205 if (!name_len)
continue;
206 size_of_labels += (3 * 4);
207 size_of_labels += name_len;
209 if (size_of_labels & 1) size_of_labels++;
211 if (size_of_labels) {
214 additional_size += 4 + 4 + size_of_labels;
218 additional_size += 4 + 4 + size_of_cue_list;
221 dst.read(reinterpret_cast<char *>(&size), 4);
222 size = qToLittleEndian<quint32>(
223 qFromLittleEndian<quint32>(size) + additional_size);
225 dst.write(reinterpret_cast<char *>(&size), 4);
228 dst.seek(dst.size());
229 if (dst.pos() & 1) dst.write(
"\000", 1);
232 dst.write(
"cue ", 4);
233 size = qToLittleEndian<quint32>(size_of_cue_list);
234 dst.write(reinterpret_cast<char *>(&size), 4);
237 size = qToLittleEndian<quint32>(labels_count);
238 dst.write(reinterpret_cast<char *>(&size), 4);
242 if (label.
isNull())
continue;
253 data = qToLittleEndian<quint32>(index);
254 dst.write(reinterpret_cast<char *>(&data), 4);
256 dst.write(reinterpret_cast<char *>(&data), 4);
257 dst.write(
"data", 4);
258 dst.write(reinterpret_cast<char *>(&data), 4);
259 dst.write(reinterpret_cast<char *>(&data), 4);
261 dst.write(reinterpret_cast<char *>(&data), 4);
266 if (size_of_labels) {
267 dst.write(
"LIST", 4);
268 size = qToLittleEndian<quint32>(size_of_labels);
269 dst.write(reinterpret_cast<char *>(&size), 4);
270 dst.write(
"adtl", 4);
273 if (label.
isNull())
continue;
274 QByteArray
name = label.
name().toUtf8();
285 dst.write(
"labl", 4);
286 data = qToLittleEndian<quint32>(name.size() + 4);
289 dst.write(reinterpret_cast<char *>(&data), 4);
290 data = qToLittleEndian<quint32>(index);
293 dst.write(reinterpret_cast<char *>(&data), 4);
294 dst.write(name.data(), name.size());
295 if (name.size() & 1) {
298 dst.write(reinterpret_cast<char *>(&data), 1);
314 const unsigned int tracks = info.
tracks();
316 unsigned int bits = info.
bits();
317 const double rate = info.
rate();
330 if (!bits) bits = 16;
333 if ((!tracks) || (!length))
return false;
334 Q_ASSERT(src.
tracks() == tracks);
335 if (src.
tracks() != tracks)
return false;
342 qWarning(
"compression mode %d not supported!",
345 i18n(
"Sorry, the currently selected compression type cannot " 346 "be used for saving. Do you want to use " 347 "G711 ULAW compression instead?"), QString(),
348 i18n(
"&Yes, use G711"),
349 i18n(
"&No, store uncompressed")
352 case (KMessageBox::Yes):
357 case (KMessageBox::No):
377 qDebug(
"auto-switching to 16 bit signed format");
382 qDebug(
"auto-switching to unsigned format");
386 qDebug(
"auto-switching to signed format");
390 if (!dst.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
392 i18n(
"Unable to open the file for saving!"));
397 if (length * ((bits + 7) / 8) >= UINT_MAX) {
402 int af_sample_format = AF_SAMPFMT_TWOSCOMP;
407 af_sample_format = AF_SAMPFMT_UNSIGNED;
410 af_sample_format = AF_SAMPFMT_FLOAT;
413 af_sample_format = AF_SAMPFMT_DOUBLE;
417 af_sample_format = AF_SAMPFMT_TWOSCOMP;
422 setup = afNewFileSetup();
423 afInitFileFormat(setup, AF_FILE_WAVE);
424 afInitChannels(setup, AF_DEFAULT_TRACK, tracks);
425 afInitSampleFormat(setup, AF_DEFAULT_TRACK, af_sample_format, bits);
426 afInitCompression(setup, AF_DEFAULT_TRACK,
428 afInitRate(setup, AF_DEFAULT_TRACK, rate);
431 outfile.
open(&outfile, setup);
433 AFfilehandle fh = outfile.
handle();
438 case AF_BAD_NOT_IMPLEMENTED:
439 reason = i18n(
"Format or function is not implemented")
443 reason = i18n(
"Out of memory");
446 reason = i18n(
"File header is damaged");
448 case AF_BAD_CODEC_TYPE:
449 reason = i18n(
"Invalid codec type")
453 reason = i18n(
"Opening the file failed");
456 reason = i18n(
"Read access failed");
459 reason = i18n(
"Invalid sample format");
462 reason = reason.number(outfile.
lastError());
465 QString text= i18n(
"An error occurred while opening the "\
466 "file:\n'%1'", reason);
473 #if Q_BYTE_ORDER == Q_BIG_ENDIAN 474 afSetVirtualByteOrder(fh, AF_DEFAULT_TRACK, AF_BYTEORDER_BIGENDIAN);
476 afSetVirtualByteOrder(fh, AF_DEFAULT_TRACK, AF_BYTEORDER_LITTLEENDIAN);
478 afSetVirtualSampleFormat(fh, AF_DEFAULT_TRACK,
483 afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, 1));
484 const unsigned int buffer_frames = (8 * 1024);
486 malloc(buffer_frames * virtual_frame_size));
487 if (!buffer)
return false;
494 unsigned int count = buffer_frames;
497 for (
unsigned int pos = 0; pos < count; pos++) {
498 for (
unsigned int track = 0; track < tracks; track++) {
501 if (!stream->
eof()) (*stream) >> sample;
513 count = afWriteFrames(fh, AF_DEFAULT_TRACK, buffer, count);
519 Q_ASSERT(rest >= count);
533 afFreeFileSetup(setup);
bool contains(const FileProperty property) const
void writeLabels(QIODevice &dst, const Kwave::LabelList &labels)
QByteArray findProperty(const Kwave::FileProperty property) const
virtual unsigned int tracks() const Q_DECL_OVERRIDE
Kwave::WavPropertyMap m_property_map
QVariant get(FileProperty key) const
void fixAudiofileBrokenHeaderBug(QIODevice &dst, Kwave::FileInfo &info, unsigned int frame_size)
virtual sample_index_t pos() const
static Kwave::Compression::Type fromInt(int i)
virtual void open(Kwave::VirtualAudioFile *x, AFfilesetup setup)
virtual bool encode(QWidget *widget, Kwave::MultiTrackReader &src, QIODevice &dst, const Kwave::MetaDataList &meta_data) Q_DECL_OVERRIDE
bool containsProperty(const Kwave::FileProperty property) const
virtual ~WavEncoder() Q_DECL_OVERRIDE
void set(FileProperty key, const QVariant &value)
static int error(QWidget *widget, QString message, QString caption=QString())
sample_index_t length() const
const QMap< FileProperty, QVariant > properties() const
void writeInfoChunk(QIODevice &dst, Kwave::FileInfo &info)
virtual Encoder * instance() Q_DECL_OVERRIDE
QList< Kwave::FileProperty > properties() const
virtual QString name() const
static int warningYesNoCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonYes=QString(), const QString buttonNo=QString(), const QString &dontAskAgainName=QString())
static int toAudiofile(Kwave::Compression::Type compression)
#define REGISTER_MIME_TYPES
virtual QList< Kwave::FileProperty > supportedProperties() Q_DECL_OVERRIDE
unsigned int tracks() const
void setBits(unsigned int bits)
#define REGISTER_COMPRESSION_TYPES
#define SAMPLE_STORAGE_BITS
unsigned int bits() const
static double zero(double)