traverso-commit
[Top][All Lists]
Advanced

[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 &lt;-> 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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]