[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Traverso-commit] traverso/src audiofileio/audiofileio.pro audiof...
From: |
Ben Levitt |
Subject: |
[Traverso-commit] traverso/src audiofileio/audiofileio.pro audiof... |
Date: |
Fri, 21 Sep 2007 17:01:07 +0000 |
CVSROOT: /sources/traverso
Module name: traverso
Changes by: Ben Levitt <benjie> 07/09/21 17:01:07
Modified files:
src/audiofileio: audiofileio.pro
src/audiofileio/encode: AbstractAudioWriter.cpp
LameAudioWriter.cpp
src/traverso : ExportWidget.cpp ExportWidget.h traverso.pro
src/traverso/ui: ExportWidget.ui
Added files:
src/audiofileio/encode: VorbisAudioWriter.cpp
VorbisAudioWriter.h
Log message:
- Add Ogg encoding
- Add ui for ogg export to ExportWidget
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/audiofileio.pro?cvsroot=traverso&r1=1.10&r2=1.11
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/encode/AbstractAudioWriter.cpp?cvsroot=traverso&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/encode/LameAudioWriter.cpp?cvsroot=traverso&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/encode/VorbisAudioWriter.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/encode/VorbisAudioWriter.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/traverso/ExportWidget.cpp?cvsroot=traverso&r1=1.56&r2=1.57
http://cvs.savannah.gnu.org/viewcvs/traverso/src/traverso/ExportWidget.h?cvsroot=traverso&r1=1.15&r2=1.16
http://cvs.savannah.gnu.org/viewcvs/traverso/src/traverso/traverso.pro?cvsroot=traverso&r1=1.68&r2=1.69
http://cvs.savannah.gnu.org/viewcvs/traverso/src/traverso/ui/ExportWidget.ui?cvsroot=traverso&r1=1.17&r2=1.18
Patches:
Index: audiofileio/audiofileio.pro
===================================================================
RCS file: /sources/traverso/traverso/src/audiofileio/audiofileio.pro,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -b -r1.10 -r1.11
--- audiofileio/audiofileio.pro 21 Sep 2007 01:36:23 -0000 1.10
+++ audiofileio/audiofileio.pro 21 Sep 2007 17:01:06 -0000 1.11
@@ -20,7 +20,9 @@
encode/AbstractAudioWriter.cpp \
encode/SFAudioWriter.cpp \
encode/WPAudioWriter.cpp \
+ encode/VorbisAudioWriter.cpp \
encode/LameAudioWriter.cpp
+
HEADERS = decode/AbstractAudioReader.h \
decode/SFAudioReader.h \
decode/FlacAudioReader.h \
@@ -31,6 +33,7 @@
encode/AbstractAudioWriter.h \
encode/SFAudioWriter.h \
encode/WPAudioWriter.h \
+ encode/VorbisAudioWriter.h \
encode/LameAudioWriter.h
macx{
QMAKE_LIBDIR += /usr/local/qt/lib
Index: audiofileio/encode/AbstractAudioWriter.cpp
===================================================================
RCS file:
/sources/traverso/traverso/src/audiofileio/encode/AbstractAudioWriter.cpp,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- audiofileio/encode/AbstractAudioWriter.cpp 21 Sep 2007 01:36:24 -0000
1.7
+++ audiofileio/encode/AbstractAudioWriter.cpp 21 Sep 2007 17:01:06 -0000
1.8
@@ -23,6 +23,7 @@
#include "SFAudioWriter.h"
#include "WPAudioWriter.h"
#include "LameAudioWriter.h"
+#include "VorbisAudioWriter.h"
#include <QString>
@@ -135,11 +136,11 @@
else if (libmp3lame_is_present && type == "lame") {
return new LameAudioWriter();
}
- /*else if (type == "flac") {
- return new FlacAudioWriter();
- }
else if (type == "vorbis") {
return new VorbisAudioWriter();
+ }
+ /*else if (type == "flac") {
+ return new FlacAudioWriter();
}*/
return 0;
Index: audiofileio/encode/LameAudioWriter.cpp
===================================================================
RCS file:
/sources/traverso/traverso/src/audiofileio/encode/LameAudioWriter.cpp,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- audiofileio/encode/LameAudioWriter.cpp 21 Sep 2007 01:36:24 -0000
1.1
+++ audiofileio/encode/LameAudioWriter.cpp 21 Sep 2007 17:01:06 -0000
1.2
@@ -74,7 +74,6 @@
bool LameAudioWriter::set_format_attribute(const QString& key, const QString&
value)
{
-
if (key == "method") {
if (value == "cbr") {
m_method = 0;
Index: traverso/ExportWidget.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/traverso/ExportWidget.cpp,v
retrieving revision 1.56
retrieving revision 1.57
diff -u -b -r1.56 -r1.57
--- traverso/ExportWidget.cpp 21 Sep 2007 01:36:24 -0000 1.56
+++ traverso/ExportWidget.cpp 21 Sep 2007 17:01:07 -0000 1.57
@@ -85,6 +85,7 @@
audioTypeComboBox->addItem("WAVPACK", "wavpack");
}
audioTypeComboBox->addItem("MP3", "mp3");
+ audioTypeComboBox->addItem("OGG", "ogg");
bitdepthComboBox->setCurrentIndex(bitdepthComboBox->findData(16));
@@ -134,6 +135,30 @@
connect(mp3MethodComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(mp3_method_changed(int)));
+ // Ogg Options Setup
+ oggMethodComboBox->addItem("Constant Bitrate", "manual");
+ oggMethodComboBox->addItem("Variable Bitrate", "vbr");
+
+ oggBitrateComboBox->addItem("45", "45");
+ oggBitrateComboBox->addItem("64", "64");
+ oggBitrateComboBox->addItem("96", "96");
+ oggBitrateComboBox->addItem("112", "112");
+ oggBitrateComboBox->addItem("128", "128");
+ oggBitrateComboBox->addItem("160", "160");
+ oggBitrateComboBox->addItem("192", "192");
+ oggBitrateComboBox->addItem("224", "224");
+ oggBitrateComboBox->addItem("256", "256");
+ oggBitrateComboBox->addItem("320", "320");
+ oggBitrateComboBox->addItem("400", "400");
+
+ oggMethodComboBox->setCurrentIndex(oggMethodComboBox->findData("vbr"));
+
oggBitrateComboBox->setCurrentIndex(oggBitrateComboBox->findData("160"));
+ ogg_method_changed(oggMethodComboBox->findData("vbr"));
+
+ oggOptionsGroupBox->hide();
+ connect(oggMethodComboBox, SIGNAL(currentIndexChanged(int)), this,
SLOT(ogg_method_changed(int)));
+
+
// CD Burning stuff....
m_burnprocess = new QProcess(this);
@@ -190,9 +215,15 @@
{
if (audioTypeComboBox->itemData(index).toString() == "mp3") {
mp3OptionsGroupBox->show();
+ oggOptionsGroupBox->hide();
+ }
+ else if (audioTypeComboBox->itemData(index).toString() == "ogg") {
+ oggOptionsGroupBox->show();
+ mp3OptionsGroupBox->hide();
}
else {
mp3OptionsGroupBox->hide();
+ oggOptionsGroupBox->hide();
}
}
@@ -220,6 +251,26 @@
}
+void ExportWidget::ogg_method_changed(int index)
+{
+ QString method = oggMethodComboBox->itemData(index).toString();
+
+ if (method == "manual") {
+ oggBitrateComboBox->show();
+ oggBitrateLabel->show();
+ oggQualitySlider->hide();
+ oggQualityLabel->hide();
+ }
+ else {
+ // VBR
+ oggQualitySlider->show();
+ oggQualityLabel->show();
+ oggBitrateComboBox->hide();
+ oggBitrateLabel->hide();
+ }
+}
+
+
void ExportWidget::on_exportStartButton_clicked( )
{
if (!is_safe_to_export()) {
@@ -247,6 +298,11 @@
m_exportSpec->writerType = "sndfile";
m_exportSpec->extraFormat["filetype"] = "flac";
}
+ else if (audioType == "wavpack") {
+ m_exportSpec->writerType = "wavpack";
+ m_exportSpec->extraFormat["quality"] = "high";
+ m_exportSpec->extraFormat["skip_wvx"] = "true";
+ }
else if (audioType == "mp3") {
m_exportSpec->writerType = "lame";
m_exportSpec->extraFormat["method"] =
mp3MethodComboBox->itemData(mp3MethodComboBox->currentIndex()).toString();
@@ -254,10 +310,16 @@
m_exportSpec->extraFormat["maxBitrate"] =
mp3MaxBitrateComboBox->itemData(mp3MaxBitrateComboBox->currentIndex()).toString();
m_exportSpec->extraFormat["quality"] =
QString::number(mp3QualitySlider->value());
}
- else if (audioType == "wavpack") {
- m_exportSpec->writerType = "wavpack";
- m_exportSpec->extraFormat["quality"] = "high";
- m_exportSpec->extraFormat["skip_wvx"] = "true";
+ else if (audioType == "ogg") {
+ m_exportSpec->writerType = "vorbis";
+ m_exportSpec->extraFormat["mode"] =
oggMethodComboBox->itemData(oggMethodComboBox->currentIndex()).toString();
+ if (m_exportSpec->extraFormat["mode"] == "manual") {
+ m_exportSpec->extraFormat["bitrateNominal"] =
oggBitrateComboBox->itemData(oggBitrateComboBox->currentIndex()).toString();
+ m_exportSpec->extraFormat["bitrateUpper"] =
oggBitrateComboBox->itemData(oggBitrateComboBox->currentIndex()).toString();
+ }
+ else {
+ m_exportSpec->extraFormat["vbrQuality"] =
QString::number(oggQualitySlider->value());
+ }
}
m_exportSpec->data_width =
bitdepthComboBox->itemData(channelComboBox->currentIndex()).toInt();
Index: traverso/ExportWidget.h
===================================================================
RCS file: /sources/traverso/traverso/src/traverso/ExportWidget.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- traverso/ExportWidget.h 21 Sep 2007 01:36:24 -0000 1.15
+++ traverso/ExportWidget.h 21 Sep 2007 17:01:07 -0000 1.16
@@ -93,6 +93,7 @@
void audio_type_changed(int index);
void mp3_method_changed(int index);
+ void ogg_method_changed(int index);
void start_burn_process();
void stop_burn_process();
Index: traverso/traverso.pro
===================================================================
RCS file: /sources/traverso/traverso/src/traverso/traverso.pro,v
retrieving revision 1.68
retrieving revision 1.69
diff -u -b -r1.68 -r1.69
--- traverso/traverso.pro 21 Sep 2007 01:36:24 -0000 1.68
+++ traverso/traverso.pro 21 Sep 2007 17:01:07 -0000 1.69
@@ -22,6 +22,7 @@
-ltraversoplugins \
-lsndfile \
-lsamplerate \
+ -lvorbisenc \
-lfftw3
HEADERS += \
Index: traverso/ui/ExportWidget.ui
===================================================================
RCS file: /sources/traverso/traverso/src/traverso/ui/ExportWidget.ui,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- traverso/ui/ExportWidget.ui 21 Sep 2007 01:36:24 -0000 1.17
+++ traverso/ui/ExportWidget.ui 21 Sep 2007 17:01:07 -0000 1.18
@@ -23,16 +23,6 @@
<number>6</number>
</property>
<item>
- <layout class="QVBoxLayout" >
- <property name="margin" >
- <number>0</number>
- </property>
- <property name="spacing" >
- <number>6</number>
- </property>
- </layout>
- </item>
- <item>
<widget class="QTabWidget" name="tabWidget" >
<property name="enabled" >
<bool>true</bool>
@@ -463,6 +453,147 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="oggOptionsGroupBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title" >
+ <string>Ogg Options</string>
+ </property>
+ <layout class="QGridLayout" >
+ <property name="margin" >
+ <number>9</number>
+ </property>
+ <property name="spacing" >
+ <number>6</number>
+ </property>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="oggBitrateLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>4</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Bitrate</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="oggBitrateComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QSlider" name="oggQualitySlider" >
+ <property name="layoutDirection" >
+ <enum>Qt::LeftToRight</enum>
+ </property>
+ <property name="autoFillBackground" >
+ <bool>false</bool>
+ </property>
+ <property name="minimum" >
+ <number>0</number>
+ </property>
+ <property name="maximum" >
+ <number>10</number>
+ </property>
+ <property name="pageStep" >
+ <number>1</number>
+ </property>
+ <property name="value" >
+ <number>7</number>
+ </property>
+ <property name="tracking" >
+ <bool>true</bool>
+ </property>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="invertedAppearance" >
+ <bool>false</bool>
+ </property>
+ <property name="invertedControls" >
+ <bool>false</bool>
+ </property>
+ <property name="tickPosition" >
+ <enum>QSlider::TicksAbove</enum>
+ </property>
+ <property name="tickInterval" >
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="oggMethodComboBox" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>5</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="oggQualityLabel" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>4</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Quality (Smallest <-> Best)</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_17" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>4</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text" >
+ <string>Encoding Method</string>
+ </property>
+ <property name="alignment" >
+ <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
Index: audiofileio/encode/VorbisAudioWriter.cpp
===================================================================
RCS file: audiofileio/encode/VorbisAudioWriter.cpp
diff -N audiofileio/encode/VorbisAudioWriter.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ audiofileio/encode/VorbisAudioWriter.cpp 21 Sep 2007 17:01:06 -0000
1.1
@@ -0,0 +1,371 @@
+/*
+Copyright (C) 2007 Ben Levitt
+ * Based on the ogg encoder module for K3b.
+ * Copyright (C) 1998-2007 Sebastian Trueg <address@hidden>
+
+This file is part of Traverso
+
+Traverso 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "VorbisAudioWriter.h"
+
+#include <stdio.h>
+#include <vorbis/vorbisenc.h>
+
+// for the random generator
+#include <stdlib.h>
+#include <time.h>
+
+#include <QString>
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+// This just exists to keep lame types private and out of LameAudioWriter.h
+class VorbisAudioWriter::Private
+{
+public:
+ Private()
+ : manualBitrate(false),
+ qualityLevel(4),
+ bitrateUpper(-1),
+ bitrateNominal(-1),
+ bitrateLower(-1),
+ sampleRate(0),
+ oggStream(0),
+ oggPage(0),
+ oggPacket(0),
+ vorbisInfo(0),
+ vorbisComment(0),
+ vorbisDspState(0),
+ vorbisBlock(0),
+ fid(0),
+ headersWritten(false) {
+ }
+
+ // encoding settings
+ bool manualBitrate;
+ // 0 to 10 -> 0.0 - 1.0
+ int qualityLevel;
+ int bitrateUpper;
+ int bitrateNominal;
+ int bitrateLower;
+ int sampleRate;
+
+ // encoding structures
+ ogg_stream_state *oggStream; // take physical pages, weld into a
logical stream of packets
+ ogg_page *oggPage; // one Ogg bitstream page. Vorbis
packets are inside
+ ogg_packet *oggPacket; // one raw packet of data for decode
+ vorbis_info *vorbisInfo; // struct that stores all the static
vorbis bitstream settings
+ vorbis_comment *vorbisComment; // struct that stores all the user
comments
+ vorbis_dsp_state *vorbisDspState; // central working state for the
packet->PCM decoder
+ vorbis_block *vorbisBlock; // local working space for
packet->PCM decode
+
+ FILE *fid;
+ bool headersWritten;
+};
+
+
+VorbisAudioWriter::VorbisAudioWriter()
+ : AbstractAudioWriter()
+{
+ d = new Private();
+}
+
+
+VorbisAudioWriter::~VorbisAudioWriter()
+{
+ cleanup();
+ delete d;
+}
+
+
+const char* VorbisAudioWriter::get_extension()
+{
+ return ".ogg";
+}
+
+
+bool VorbisAudioWriter::set_format_attribute(const QString& key, const
QString& value)
+{
+ if (key == "mode") {
+ d->manualBitrate = (value == "manual");
+ return true;
+ }
+ else if (key == "bitrateLower") {
+ d->bitrateLower = value.toInt();
+ return true;
+ }
+ else if (key == "bitrateNominal") {
+ d->bitrateNominal = value.toInt();
+ return true;
+ }
+ else if (key == "bitrateUpper") {
+ d->bitrateUpper = value.toInt();
+ return true;
+ }
+ else if (key == "vbrQuality") { // -1 to 10
+ d->qualityLevel = value.toInt();
+ return true;
+ }
+
+ return false;
+}
+
+
+bool VorbisAudioWriter::open_private()
+{
+ cleanup();
+
+ d->fid = fopen(m_fileName.toUtf8().data(), "w+");
+ if (!d->fid) {
+ return false;
+ }
+
+ d->oggPage = new ogg_page;
+ d->oggPacket = new ogg_packet;
+ d->vorbisInfo = new vorbis_info;
+
+ vorbis_info_init(d->vorbisInfo);
+
+ int ret = 0;
+
+ if (d->manualBitrate) {
+ ret = vorbis_encode_init(d->vorbisInfo,
+ m_channels,
+ m_rate,
+ d->bitrateUpper != -1 ?
d->bitrateUpper*1000 : -1,
+ d->bitrateNominal != -1 ?
d->bitrateNominal*1000 : -1,
+ d->bitrateLower != -1 ?
d->bitrateLower*1000 : -1 );
+ }
+ else {
+ if (d->qualityLevel < -1) {
+ d->qualityLevel = -1;
+ }
+ else if (d->qualityLevel > 10) {
+ d->qualityLevel = 10;
+ }
+
+ ret = vorbis_encode_init_vbr(d->vorbisInfo,
+ m_channels,
+ m_rate,
+ (float)d->qualityLevel/10.0);
+ }
+
+ if (ret) {
+ PERROR("vorbis_encode_init failed: %d", ret);
+ cleanup();
+ return false;
+ }
+
+ // init the comment stuff
+ d->vorbisComment = new vorbis_comment;
+ vorbis_comment_init(d->vorbisComment);
+
+ // add the encoder tag (so everybody knows we did it! ;)
+ vorbis_comment_add_tag(d->vorbisComment, "ENCODER", "Traverso");
+
+ // set up the analysis state and auxiliary encoding storage
+ d->vorbisDspState = new vorbis_dsp_state;
+ d->vorbisBlock = new vorbis_block;
+ vorbis_analysis_init(d->vorbisDspState, d->vorbisInfo);
+ vorbis_block_init(d->vorbisDspState, d->vorbisBlock);
+
+ // set up our packet->stream encoder
+ // pick a random serial number; that way we can more likely build
+ // chained streams just by concatenation
+ d->oggStream = new ogg_stream_state;
+ srand(time(0));
+ ogg_stream_init(d->oggStream, rand());
+
+ return true;
+}
+
+
+bool VorbisAudioWriter::writeOggHeaders()
+{
+ if (!d->oggStream) {
+ PERROR("call to writeOggHeaders without init.");
+ return false;
+ }
+ if (d->headersWritten) {
+ PERROR("headers already written.");
+ return true;
+ }
+
+ //
+ // Vorbis streams begin with three headers; the initial header (with
+ // most of the codec setup parameters) which is mandated by the Ogg
+ // bitstream spec. The second header holds any comment fields. The
+ // third header holds the bitstream codebook. We merely need to
+ // make the headers, then pass them to libvorbis one at a time;
+ // libvorbis handles the additional Ogg bitstream constraints
+ //
+ ogg_packet header;
+ ogg_packet header_comm;
+ ogg_packet header_code;
+
+ vorbis_analysis_headerout(d->vorbisDspState,
+ d->vorbisComment,
+ &header,
+ &header_comm,
+ &header_code);
+
+ // automatically placed in its own page
+ ogg_stream_packetin(d->oggStream, &header);
+ ogg_stream_packetin(d->oggStream, &header_comm);
+ ogg_stream_packetin(d->oggStream, &header_code);
+
+ //
+ // This ensures the actual
+ // audio data will start on a new page, as per spec
+ //
+ QByteArray data;
+ while (ogg_stream_flush(d->oggStream, d->oggPage)) {
+ fwrite((char*)d->oggPage->header, 1, d->oggPage->header_len,
d->fid);
+ fwrite((char*)d->oggPage->body, 1, d->oggPage->body_len,
d->fid);
+ }
+
+ d->headersWritten = true;
+
+ return true;
+}
+
+
+nframes_t VorbisAudioWriter::write_private(void* buffer, nframes_t frameCount)
+{
+ if (!d->headersWritten) {
+ if (!writeOggHeaders()) {
+ return 0;
+ }
+ }
+
+ char* data = (char*)buffer;
+
+ // expose the buffer to submit data
+ float** writeBuffer = vorbis_analysis_buffer(d->vorbisDspState,
frameCount);
+
+ // uninterleave samples
+ if (m_channels == 1) {
+ for (int i = 0; i < frameCount; i++) {
+ // FIXME: Currently assumes 16bit audio
+ writeBuffer[0][i]=( (data[i*4+1]<<8) |
(0x00ff&(int)data[i*4]) ) / 32768.f;
+ }
+ }
+ else {
+ for (int i = 0; i < frameCount; i++) {
+ // FIXME: Currently assumes 16bit audio
+ writeBuffer[0][i]=( (data[i*4+1]<<8) |
(0x00ff&(int)data[i*4]) ) / 32768.f;
+ writeBuffer[1][i]=( (data[i*4+3]<<8) |
(0x00ff&(int)data[i*4+2]) ) / 32768.f;
+ }
+ }
+
+ // tell the library how much we actually submitted
+ vorbis_analysis_wrote(d->vorbisDspState, frameCount);
+
+ return flushVorbis();
+}
+
+
+long VorbisAudioWriter::flushVorbis()
+{
+ // vorbis does some data preanalysis, then divvies up blocks for
+ // more involved (potentially parallel) processing. Get a single
+ // block for encoding now
+ long writtenData = 0;
+
+ while (vorbis_analysis_blockout( d->vorbisDspState, d->vorbisBlock ) ==
1) {
+ // analysis
+ vorbis_analysis(d->vorbisBlock, 0);
+ vorbis_bitrate_addblock(d->vorbisBlock);
+
+ while (vorbis_bitrate_flushpacket(d->vorbisDspState,
d->oggPacket)) {
+ // weld the packet into the bitstream
+ ogg_stream_packetin(d->oggStream, d->oggPacket);
+
+ // write out pages (if any)
+ while (ogg_stream_pageout(d->oggStream, d->oggPage)) {
+ fwrite((char*)d->oggPage->header, 1,
d->oggPage->header_len, d->fid);
+ fwrite((char*)d->oggPage->body, 1,
d->oggPage->body_len, d->fid);
+
+ writtenData += (d->oggPage->header_len +
d->oggPage->body_len);
+ }
+ }
+ }
+
+ return writtenData;
+}
+
+
+void VorbisAudioWriter::cleanup()
+{
+ if (d->oggStream) {
+ ogg_stream_clear(d->oggStream);
+ delete d->oggStream;
+ d->oggStream = 0;
+ }
+ if (d->vorbisBlock) {
+ vorbis_block_clear(d->vorbisBlock);
+ delete d->vorbisBlock;
+ d->vorbisBlock = 0;
+ }
+ if (d->vorbisDspState) {
+ vorbis_dsp_clear(d->vorbisDspState);
+ delete d->vorbisDspState;
+ d->vorbisDspState = 0;
+ }
+ if (d->vorbisComment) {
+ vorbis_comment_clear(d->vorbisComment);
+ delete d->vorbisComment;
+ d->vorbisComment = 0;
+ }
+ if (d->vorbisInfo) {
+ vorbis_info_clear(d->vorbisInfo);
+ delete d->vorbisInfo;
+ d->vorbisInfo = 0;
+ }
+
+ // ogg_page and ogg_packet structs always point to storage in
+ // libvorbis. They're never freed or manipulated directly
+ if (d->oggPage) {
+ delete d->oggPage;
+ d->oggPage = 0;
+ }
+ if (d->oggPacket) {
+ delete d->oggPacket;
+ d->oggPacket = 0;
+ }
+ if (d->fid) {
+ fclose(d->fid);
+ d->fid = 0;
+ }
+
+ d->headersWritten = false;
+}
+
+
+void VorbisAudioWriter::close_private()
+{
+ if (d->vorbisDspState) {
+ vorbis_analysis_wrote(d->vorbisDspState, 0);
+ flushVorbis();
+ }
+ cleanup();
+}
+
Index: audiofileio/encode/VorbisAudioWriter.h
===================================================================
RCS file: audiofileio/encode/VorbisAudioWriter.h
diff -N audiofileio/encode/VorbisAudioWriter.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ audiofileio/encode/VorbisAudioWriter.h 21 Sep 2007 17:01:07 -0000
1.1
@@ -0,0 +1,54 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef VORBISAUDIOWRITER_H
+#define VORBISAUDIOWRITER_H
+
+#include "AbstractAudioWriter.h"
+#include "defines.h"
+
+
+class QString;
+
+class VorbisAudioWriter : public AbstractAudioWriter
+{
+ Q_OBJECT
+
+public:
+ VorbisAudioWriter();
+ ~VorbisAudioWriter();
+
+ bool set_format_attribute(const QString& key, const QString& value);
+ const char* get_extension();
+
+protected:
+ bool open_private();
+ bool writeOggHeaders();
+ nframes_t write_private(void* buffer, nframes_t frameCount);
+ long flushVorbis();
+ void cleanup();
+ void close_private();
+
+ class Private;
+ Private* d;
+};
+
+#endif