85eeb7af7faf — Chris Cannam 14 days ago
First cut at Opus file writer
M bqaudiostream/AudioWriteStream.h +1 -1
@@ 74,7 74,7 @@ public:
     /**
      * May throw FileOperationFailed if encoding fails.
      */
-    virtual void putInterleavedFrames(size_t frameCount, float *frames) = 0;
+    virtual void putInterleavedFrames(size_t frameCount, const float *frames) = 0;
     
 protected:
     AudioWriteStream(Target t) : m_target(t) { }

          
M build/Makefile.inc +3 -1
@@ 4,7 4,7 @@ HEADERS	:= $(wildcard src/*.h) $(wildcar
 OBJECTS	:= $(patsubst %.cpp,%.o,$(SOURCES))
 LIBRARY	:= libbqaudiostream.a
 
-CXXFLAGS := -std=c++98 $(AUDIOSTREAM_DEFINES) -I../bqvec -I../bqthingfactory -I../bqresample -I./bqaudiostream -fpic $(THIRD_PARTY_INCLUDES)
+CXXFLAGS := -std=c++98 -Wall $(AUDIOSTREAM_DEFINES) -I../bqvec -I../bqthingfactory -I../bqresample -I./bqaudiostream -fpic $(THIRD_PARTY_INCLUDES)
 
 all:	$(LIBRARY)
 

          
@@ 44,6 44,7 @@ src/AudioWriteStreamFactory.o: src/Simpl
 src/AudioWriteStreamFactory.o: src/SimpleWavFileWriteStream.h
 src/AudioWriteStreamFactory.o: src/CoreAudioWriteStream.cpp
 src/AudioWriteStreamFactory.o: src/CoreAudioWriteStream.h
+src/AudioWriteStreamFactory.o: src/OpusWriteStream.cpp
 src/AudioStreamExceptions.o: ./bqaudiostream/Exceptions.h
 src/CoreAudioReadStream.o: ./bqaudiostream/AudioReadStream.h
 src/CoreAudioWriteStream.o: ./bqaudiostream/AudioWriteStream.h

          
@@ 55,3 56,4 @@ src/SimpleWavFileReadStream.o: ./bqaudio
 src/SimpleWavFileWriteStream.o: ./bqaudiostream/AudioWriteStream.h
 src/WavFileReadStream.o: ./bqaudiostream/AudioReadStream.h
 src/WavFileWriteStream.o: ./bqaudiostream/AudioWriteStream.h
+src/OpusWriteStream.o: ./bqaudiostream/AudioWriteStream.h

          
M src/AudioWriteStreamFactory.cpp +1 -0
@@ 137,4 137,5 @@ AudioWriteStreamFactory::isExtensionSupp
 #include "WavFileWriteStream.cpp"
 #include "SimpleWavFileWriteStream.cpp"
 #include "CoreAudioWriteStream.cpp"
+#include "OpusWriteStream.cpp"
 

          
M src/CoreAudioWriteStream.cpp +2 -2
@@ 197,14 197,14 @@ CoreAudioWriteStream::~CoreAudioWriteStr
 }
 
 void
-CoreAudioWriteStream::putInterleavedFrames(size_t count, float *frames)
+CoreAudioWriteStream::putInterleavedFrames(size_t count, const float *frames)
 {
     if (count == 0) return;
 
     m_d->buffer.mBuffers[0].mDataByteSize =
         sizeof(float) * getChannelCount() * count;
     
-    m_d->buffer.mBuffers[0].mData = frames;
+    m_d->buffer.mBuffers[0].mData = (void *)frames;
 
     UInt32 framesToWrite = count;
 

          
M src/CoreAudioWriteStream.h +2 -2
@@ 32,8 32,8 @@ 
     Software without prior written authorization.
 */
 
-#ifndef BQ_CORE_AUDIO_WRITE_STREAM_H_
-#define BQ_CORE_AUDIO_WRITE_STREAM_H_
+#ifndef BQ_CORE_AUDIO_WRITE_STREAM_H
+#define BQ_CORE_AUDIO_WRITE_STREAM_H
 
 #include "AudioWriteStream.h"
 

          
M src/OpusReadStream.cpp +1 -1
@@ 5,7 5,7 @@ 
     A small library wrapping various audio file read/write
     implementations in C++.
 
-    Copyright 2007-2015 Particular Programs Ltd.
+    Copyright 2007-2020 Particular Programs Ltd.
 
     Permission is hereby granted, free of charge, to any person
     obtaining a copy of this software and associated documentation

          
A => src/OpusWriteStream.cpp +129 -0
@@ 0,0 1,129 @@ 
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    bqaudiostream
+
+    A small library wrapping various audio file read/write
+    implementations in C++.
+
+    Copyright 2007-2020 Particular Programs Ltd.
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of Chris Cannam and
+    Particular Programs Ltd shall not be used in advertising or
+    otherwise to promote the sale, use or other dealings in this
+    Software without prior written authorization.
+*/
+
+#ifdef HAVE_OPUS
+
+#include "OpusWriteStream.h"
+
+#include <opus/opusenc.h>
+
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+namespace breakfastquay
+{
+
+static vector<string>
+getOpusWriteExtensions()
+{
+    vector<string> extensions;
+    extensions.push_back("opus");
+    return extensions;
+}
+
+static 
+AudioWriteStreamBuilder<OpusWriteStream>
+coreaudiowritebuilder(
+    string("http://breakfastquay.com/rdf/turbot/audiostream/OpusWriteStream"),
+    getOpusWriteExtensions()
+    );
+
+class OpusWriteStream::D
+{
+public:
+    D() : encoder(0) { }
+
+    OggOpusEnc *encoder;
+};
+
+OpusWriteStream::OpusWriteStream(Target target) :
+    AudioWriteStream(target),
+    m_d(new D)
+{
+    cerr << "OpusWriteStream: file is " << getPath() << ", channel count is " << getChannelCount() << ", sample rate " << getSampleRate() << endl;
+
+    //!!! +windows file encoding?
+
+    int err = 0;
+    m_d->encoder = ope_encoder_create_file(getPath().c_str(), 0,
+                                           getSampleRate(), getChannelCount(),
+                                           getChannelCount() > 2 ? 1 : 0,
+                                           &err);
+
+    if (err || !m_d->encoder) {
+        ostringstream os;    
+        os << "OpusWriteStream: Unable to open file for writing (error code "
+           << err << ")";
+        m_error = os.str();
+        cerr << m_error << endl;
+        m_d->encoder = 0;
+        throw FailedToWriteFile(getPath());
+    }    
+}
+
+OpusWriteStream::~OpusWriteStream()
+{
+    if (m_d->encoder) {
+        cerr << "OpusWriteStream::~OpusWriteStream: closing" << endl;
+        int err = ope_encoder_drain(m_d->encoder);
+        if (err) {
+            cerr << "WARNING: ope_encoder_drain failed (error code "
+                 << err << ")" << endl;
+        }
+        ope_encoder_destroy(m_d->encoder);
+    }
+}
+
+void
+OpusWriteStream::putInterleavedFrames(size_t count, const float *frames)
+{
+    if (count == 0 || !m_d->encoder) return;
+
+    int err = ope_encoder_write_float(m_d->encoder, frames, count);
+
+    if (err) {
+        ostringstream os;    
+        os << "OpusWriteStream: Failed to write frames to encoder (error code "
+           << err << ")";
+        m_error = os.str();
+        cerr << m_error << endl;
+        throw FileOperationFailed(getPath(), "encode");
+    }
+}
+
+}
+
+#endif

          
A => src/OpusWriteStream.h +66 -0
@@ 0,0 1,66 @@ 
+/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
+/*
+    bqaudiostream
+
+    A small library wrapping various audio file read/write
+    implementations in C++.
+
+    Copyright 2007-2020 Particular Programs Ltd.
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation
+    files (the "Software"), to deal in the Software without
+    restriction, including without limitation the rights to use, copy,
+    modify, merge, publish, distribute, sublicense, and/or sell copies
+    of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be
+    included in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
+    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+    CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+    Except as contained in this notice, the names of Chris Cannam and
+    Particular Programs Ltd shall not be used in advertising or
+    otherwise to promote the sale, use or other dealings in this
+    Software without prior written authorization.
+*/
+
+#ifndef BQ_OPUS_WRITE_STREAM_H
+#define BQ_OPUS_WRITE_STREAM_H
+
+#include "AudioWriteStream.h"
+
+#ifdef HAVE_OPUS
+
+namespace breakfastquay
+{
+    
+class OpusWriteStream : public AudioWriteStream
+{
+public:
+    OpusWriteStream(Target target);
+    virtual ~OpusWriteStream();
+
+    virtual std::string getError() const { return m_error; }
+
+    virtual void putInterleavedFrames(size_t count, const float *frames);
+    
+protected:
+    std::string m_error;
+
+    class D;
+    D *m_d;
+};
+
+}
+
+#endif
+
+#endif

          
M src/WavFileWriteStream.cpp +1 -1
@@ 85,7 85,7 @@ WavFileWriteStream::~WavFileWriteStream(
 }
 
 void
-WavFileWriteStream::putInterleavedFrames(size_t count, float *frames)
+WavFileWriteStream::putInterleavedFrames(size_t count, const float *frames)
 {
     if (count == 0) return;
 

          
M src/WavFileWriteStream.h +1 -1
@@ 52,7 52,7 @@ public:
 
     virtual std::string getError() const { return m_error; }
 
-    virtual void putInterleavedFrames(size_t count, float *frames);
+    virtual void putInterleavedFrames(size_t count, const float *frames);
     
 protected:
     SF_INFO m_fileInfo;

          
M test/test.pro +1 -1
@@ 10,7 10,7 @@ QT -= gui
 DESTDIR = .
 QMAKE_LIBDIR += . ..
 
-LIBS += -L.. -lbqaudiostream -L../../bqresample -lbqresample -L../../bqvec -lbqvec -lsndfile -loggz -lfishsound -lopusfile -lopus -logg -lsamplerate
+LIBS += -L.. -lbqaudiostream -L../../bqresample -lbqresample -L../../bqvec -lbqvec -lsndfile -loggz -lfishsound -lopusfile -lopusenc -lopus -logg -lsamplerate
 
 INCLUDEPATH += . .. ../../bqvec ../../bqresample ../../bqthingfactory
 DEPENDPATH += . .. ../../bqvec ../../bqresample ../../bqthingfactory