summaryrefslogtreecommitdiffstats
path: root/plugins/recording
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/recording')
-rw-r--r--plugins/recording/CMakeL10n.txt6
-rw-r--r--plugins/recording/Makefile.am22
-rw-r--r--plugins/recording/encoder.cpp172
-rw-r--r--plugins/recording/encoder.h101
-rw-r--r--plugins/recording/encoder_mp3.cpp214
-rw-r--r--plugins/recording/encoder_mp3.h56
-rw-r--r--plugins/recording/encoder_ogg.cpp250
-rw-r--r--plugins/recording/encoder_ogg.h55
-rw-r--r--plugins/recording/encoder_pcm.cpp78
-rw-r--r--plugins/recording/encoder_pcm.h46
-rw-r--r--plugins/recording/icons/Makefile.am2
-rw-r--r--plugins/recording/icons/hi16-action-tderadio_record.pngbin0 -> 399 bytes
-rw-r--r--plugins/recording/icons/hi16-app-tderadio_plus_rec.pngbin0 -> 917 bytes
-rw-r--r--plugins/recording/icons/hi22-action-tderadio_record.pngbin0 -> 573 bytes
-rw-r--r--plugins/recording/icons/hi22-app-tderadio_plus_rec.pngbin0 -> 1433 bytes
-rw-r--r--plugins/recording/icons/hi256-action-tderadio_record.pngbin0 -> 5458 bytes
-rw-r--r--plugins/recording/icons/hi32-action-tderadio_record.pngbin0 -> 808 bytes
-rw-r--r--plugins/recording/icons/hi32-app-tderadio_plus_rec.pngbin0 -> 2321 bytes
-rw-r--r--plugins/recording/icons/hi48-action-tderadio_record.pngbin0 -> 1232 bytes
-rw-r--r--plugins/recording/icons/hi48-app-tderadio_plus_rec.pngbin0 -> 4193 bytes
-rw-r--r--plugins/recording/icons/hi64-action-tderadio_record.pngbin0 -> 1534 bytes
-rw-r--r--plugins/recording/icons/hi64-app-tderadio_plus_rec.pngbin0 -> 6249 bytes
-rw-r--r--plugins/recording/po/Makefile.am2
-rw-r--r--plugins/recording/po/de.po396
-rw-r--r--plugins/recording/po/ru.po391
-rw-r--r--plugins/recording/po/tderadio-recording.pot378
-rw-r--r--plugins/recording/reccfg_interfaces.cpp151
-rw-r--r--plugins/recording/reccfg_interfaces.h102
-rw-r--r--plugins/recording/recording-config.cpp215
-rw-r--r--plugins/recording/recording-config.h73
-rw-r--r--plugins/recording/recording-configuration-ui.ui726
-rw-r--r--plugins/recording/recording-configuration.cpp414
-rw-r--r--plugins/recording/recording-configuration.h127
-rw-r--r--plugins/recording/recording-datamonitor.cpp278
-rw-r--r--plugins/recording/recording-datamonitor.h67
-rw-r--r--plugins/recording/recording-monitor.cpp402
-rw-r--r--plugins/recording/recording-monitor.h125
-rw-r--r--plugins/recording/recording.cpp731
-rw-r--r--plugins/recording/recording.h149
-rw-r--r--plugins/recording/soundstreamevent.h87
40 files changed, 5816 insertions, 0 deletions
diff --git a/plugins/recording/CMakeL10n.txt b/plugins/recording/CMakeL10n.txt
new file mode 100644
index 0000000..11d0cab
--- /dev/null
+++ b/plugins/recording/CMakeL10n.txt
@@ -0,0 +1,6 @@
+##### create translation templates ##############
+
+tde_l10n_create_template(
+ CATALOG "tderadio-recording"
+ DESTINATION "po"
+)
diff --git a/plugins/recording/Makefile.am b/plugins/recording/Makefile.am
new file mode 100644
index 0000000..f45f5fb
--- /dev/null
+++ b/plugins/recording/Makefile.am
@@ -0,0 +1,22 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libtderadio_LTLIBRARIES = librecording.la
+librecording_la_SOURCES = recording-configuration.cpp \
+ recording-configuration-ui.ui recording.cpp recording-config.cpp reccfg_interfaces.cpp encoder.cpp \
+ recording-datamonitor.cpp recording-monitor.cpp encoder_mp3.cpp encoder_ogg.cpp encoder_pcm.cpp
+librecording_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+librecording_la_LIBADD = $(LIB_OGG) $(LIB_LAME)
+
+noinst_HEADERS = recording-configuration.h recording.h recording-config.h \
+ reccfg_interfaces.h encoder.h soundstreamevent.h recording-datamonitor.h \
+ recording-monitor.h encoder_mp3.h encoder_ogg.h encoder_pcm.h
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/tderadio-recording.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/tderadio-recording.pot
diff --git a/plugins/recording/encoder.cpp b/plugins/recording/encoder.cpp
new file mode 100644
index 0000000..b1c054f
--- /dev/null
+++ b/plugins/recording/encoder.cpp
@@ -0,0 +1,172 @@
+/***************************************************************************
+ encoder.cpp - description
+ -------------------
+ begin : Thu May 05 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "../../src/include/radiostation.h"
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/aboutwidget.h"
+
+#include "recording.h"
+#include "recording-configuration.h"
+#include "soundstreamevent.h"
+
+#include <tqsocketnotifier.h>
+#include <tqevent.h>
+#include <tqapplication.h>
+#include <tqregexp.h>
+
+#include <tdeconfig.h>
+#include <tdeversion.h>
+#include <tdelocale.h>
+
+RecordingEncoding::RecordingEncoding(TQObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const TQString &filename)
+ :
+ m_parent(parent),
+ m_config(cfg),
+ m_RadioStation(rs ? rs->copy() : NULL),
+ m_SoundStreamID(ssid),
+ m_error(false),
+ m_errorString(TQString()),
+ m_done(false),
+ m_InputBuffers(m_config.m_EncodeBufferCount < 3 ? 3 : m_config.m_EncodeBufferCount,
+ m_config.m_EncodeBufferSize < 4096 ? 4096 : m_config.m_EncodeBufferSize),
+ m_buffersMetaData(NULL),
+ m_encodedSize(0),
+ m_InputStartTime(0),
+ m_InputStartPosition(0),
+ m_outputURL(filename)
+{
+
+ if (m_config.m_EncodeBufferCount < 3)
+ m_config.m_EncodeBufferCount = 3;
+ if (m_config.m_EncodeBufferSize < 4096)
+ m_config.m_EncodeBufferSize = 4096;
+
+ m_buffersMetaData = new TQPtrList<BufferSoundMetaData> *[m_config.m_EncodeBufferCount];
+ for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) {
+ m_buffersMetaData [i] = new TQPtrList<BufferSoundMetaData>;
+ m_buffersMetaData [i]->setAutoDelete(true);
+ }
+}
+
+
+RecordingEncoding::~RecordingEncoding()
+{
+ for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) {
+ delete m_buffersMetaData[i];
+ }
+ delete m_buffersMetaData;
+ delete m_RadioStation;
+}
+
+
+char *RecordingEncoding::lockInputBuffer(size_t &bufferSize)
+{
+ if (m_done || m_error)
+ return NULL;
+ char * retval = m_InputBuffers.lockWriteBuffer(bufferSize);
+
+ m_error |= m_InputBuffers.hasError();
+ m_errorString += m_InputBuffers.getErrorString();
+ m_InputBuffers.resetError();
+
+ return retval;
+}
+
+
+void RecordingEncoding::unlockInputBuffer(size_t bufferSize, const SoundMetaData &md)
+{
+ if (m_done)
+ return;
+ size_t bufidx = m_InputBuffers.getCurrentWriteBufferIdx();
+ size_t buffill = m_InputBuffers.getWriteBufferFill();
+ m_InputBuffers.unlockWriteBuffer(bufferSize);
+
+ if (!m_InputBuffers.hasError()) {
+ if (!m_InputStartTime) {
+ m_InputStartTime = md.absoluteTimestamp();
+ m_InputStartPosition = md.position();
+ }
+ BufferSoundMetaData *bmd = new BufferSoundMetaData(
+ md.position() - m_InputStartPosition,
+ md.absoluteTimestamp() - m_InputStartTime,
+ md.absoluteTimestamp(),
+ md.url(),
+ buffill);
+ m_buffersMetaData[bufidx]->append(bmd);
+ } else {
+ m_error = true;
+ m_errorString += m_InputBuffers.getErrorString();
+ m_InputBuffers.resetError();
+ }
+}
+
+
+void RecordingEncoding::setDone()
+{
+ m_done = true;
+ m_InputBuffers.unlockAllWriteBuffers();
+}
+
+
+
+void RecordingEncoding::run()
+{
+ BufferSoundMetaData last_md;
+
+ while (!m_error) {
+ char *buffer = NULL;
+ size_t buffer_fill = 0;
+ if (!m_done) {
+ buffer = m_InputBuffers.wait4ReadBuffer(buffer_fill);
+ }
+
+ if (!buffer_fill) {
+ if (m_done)
+ break;
+ else
+ continue;
+ }
+
+ char *export_buffer = NULL;
+ size_t export_buffer_size = 0;
+
+ TQ_UINT64 old_pos = m_encodedSize;
+
+ encode(buffer, buffer_fill, export_buffer, export_buffer_size);
+
+ SoundStreamEncodingStepEvent *step_event = NULL;
+
+ if (!m_error) {
+ last_md = *m_buffersMetaData[m_InputBuffers.getCurrentReadBufferIdx()]->first();
+ SoundMetaData md(old_pos, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL);
+ step_event = new SoundStreamEncodingStepEvent(m_SoundStreamID, export_buffer, export_buffer_size, md);
+ }
+
+ if (step_event)
+ TQApplication::postEvent(m_parent, step_event);
+ }
+ m_done = true;
+ closeOutput();
+
+ SoundMetaData md(m_encodedSize, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL);
+ TQApplication::postEvent(m_parent, new SoundStreamEncodingStepEvent(m_SoundStreamID, NULL, 0, md));
+
+ TQApplication::postEvent(m_parent, new SoundStreamEncodingTerminatedEvent(m_SoundStreamID));
+}
+
diff --git a/plugins/recording/encoder.h b/plugins/recording/encoder.h
new file mode 100644
index 0000000..b0c442d
--- /dev/null
+++ b/plugins/recording/encoder.h
@@ -0,0 +1,101 @@
+/***************************************************************************
+ encoder.h - description
+ -------------------
+ begin : Thu May 05 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_H
+#define KRADIO_RECORDING_ENCODER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqthread.h>
+
+#include "../../src/include/radiostation.h"
+#include "../../src/include/multibuffer.h"
+#include "../../src/include/sound_metadata.h"
+#include "../../src/include/soundstreamid.h"
+#include "recording-config.h"
+
+class BufferSoundMetaData : public SoundMetaData
+{
+public:
+ BufferSoundMetaData()
+ : SoundMetaData(0, 0, 0, KURL()), m_BufferPosition(0) {}
+ BufferSoundMetaData(const SoundMetaData &md, size_t bufferpos)
+ : SoundMetaData(md), m_BufferPosition(bufferpos) {}
+ BufferSoundMetaData(TQ_INT64 pos, time_t rel, time_t abs, const KURL &url, size_t bufferpos)
+ : SoundMetaData(pos, rel, abs, url), m_BufferPosition(bufferpos) {}
+
+ size_t bufferPosition() const { return m_BufferPosition; }
+
+protected:
+ size_t m_BufferPosition;
+};
+
+
+class RecordingEncoding : public TQThread
+{
+public:
+ RecordingEncoding(TQObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const TQString &filename);
+ virtual ~RecordingEncoding();
+
+ void run();
+
+ char *lockInputBuffer(size_t &bufferSize); // bytes we whish to write, returns number of bytes available
+ void unlockInputBuffer(size_t bufferSize, const SoundMetaData &md); // bytes we actually wrote
+
+ bool error() const { return m_error; }
+ const TQString &errorString() const { return m_errorString; }
+
+ void setDone();
+ bool IsDone() { return m_done; }
+
+ virtual bool openOutput(const TQString &outputFile) = 0;
+ virtual void closeOutput() = 0;
+
+ TQ_UINT64 encodedSize() const { return m_encodedSize; }
+
+ const RecordingConfig &config() const { return m_config; }
+
+protected:
+ virtual void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) = 0;
+
+ TQObject *m_parent;
+ RecordingConfig m_config;
+ RadioStation *m_RadioStation;
+ SoundStreamID m_SoundStreamID;
+
+ bool m_error;
+ TQString m_errorString;
+ bool m_done;
+
+ MultiBuffer m_InputBuffers;
+ TQPtrList<BufferSoundMetaData>
+ **m_buffersMetaData;
+ TQ_UINT64 m_encodedSize;
+
+ time_t m_InputStartTime;
+ TQ_UINT64 m_InputStartPosition;
+
+ KURL m_outputURL;
+};
+
+
+#endif
diff --git a/plugins/recording/encoder_mp3.cpp b/plugins/recording/encoder_mp3.cpp
new file mode 100644
index 0000000..456850f
--- /dev/null
+++ b/plugins/recording/encoder_mp3.cpp
@@ -0,0 +1,214 @@
+/***************************************************************************
+ encoder_mp3.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "encoder_mp3.h"
+
+#include <tqmutex.h>
+#include <tdelocale.h>
+
+RecordingEncodingMP3::RecordingEncodingMP3(TQObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const TQString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename)
+#ifdef HAVE_LAME
+ ,
+ m_MP3Buffer(NULL),
+ m_MP3BufferSize(0),
+ m_MP3Output(NULL),
+ m_ID3Tags(NULL),
+ m_LAMEFlags(NULL),
+ m_MP3LBuffer(NULL),
+ m_MP3RBuffer(NULL)
+#endif
+{
+ m_config.m_OutputFormat = RecordingConfig::outputMP3;
+ m_config.m_SoundFormat.m_Encoding = "mp3";
+ openOutput(filename);
+}
+
+
+RecordingEncodingMP3::~RecordingEncodingMP3()
+{
+ closeOutput();
+}
+
+
+static TQMutex lameSerialization;
+
+void RecordingEncodingMP3::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+
+#ifdef HAVE_LAME
+ short int *buffer = (short int*)_buffer;
+ size_t j = 0,
+ j_inc = (m_config.m_SoundFormat.m_Channels == 1) ? 1 : 2,
+ dj = (m_config.m_SoundFormat.m_Channels == 1) ? 0 : 1,
+ samples = buffer_size / m_config.m_SoundFormat.frameSize();
+
+ for (size_t i = 0; i < samples; ++i, j+=j_inc) {
+ m_MP3LBuffer[i] = buffer[j];
+ m_MP3RBuffer[i] = buffer[j+dj];
+ }
+
+ int n = 0;
+ lameSerialization.lock();
+ n = lame_encode_buffer(m_LAMEFlags,
+ m_MP3LBuffer,
+ m_MP3RBuffer,
+ samples,
+ m_MP3Buffer,
+ m_MP3BufferSize);
+ lameSerialization.unlock();
+ if (n < 0) {
+ m_errorString += i18n("Error %1 while encoding mp3. ").arg(TQString().setNum(n));
+ m_error = true;
+ } else if (n > 0) {
+ m_encodedSize += n;
+
+ export_buffer = (char*)m_MP3Buffer;
+ export_buffer_size = n;
+ int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output);
+
+ if (r <= 0) {
+ m_errorString += i18n("Error %1 writing output. ").arg(TQString().setNum(r));
+ m_error = true;
+ }
+ }
+#endif
+}
+
+
+
+bool RecordingEncodingMP3::openOutput(const TQString &output)
+{
+#ifdef HAVE_LAME
+// m_output = NULL;
+ m_LAMEFlags = lame_init();
+
+ if (!m_LAMEFlags) {
+ m_error = true;
+ m_errorString += i18n("Cannot initialize lalibmp3lame. ");
+ } else {
+ lame_set_in_samplerate(m_LAMEFlags, m_config.m_SoundFormat.m_SampleRate);
+ lame_set_num_channels(m_LAMEFlags, 2);
+ //lame_set_quality(m_LAMEFlags, m_config.mp3Quality);
+
+ lame_set_mode(m_LAMEFlags, m_config.m_SoundFormat.m_Channels == 1 ? MONO : JOINT_STEREO);
+
+ // lame_seterrorf(m_LAMEFlags, ...);
+ // lame_setdebugf(m_LAMEFlags, ...);
+ // lame_setmsgf(m_LAMEFlags, ...);
+
+ lame_set_VBR(m_LAMEFlags, vbr_default);
+ lame_set_VBR_q(m_LAMEFlags, m_config.m_mp3Quality);
+
+ if (lame_init_params(m_LAMEFlags) < 0) {
+ m_error = true;
+ m_errorString += i18n("Cannot initialize libmp3lame parameters. ").arg(output);
+ }
+
+ if (!m_error) {
+ id3tag_init(m_LAMEFlags);
+ id3tag_add_v2(m_LAMEFlags);
+ TQString title = m_RadioStation->name() + TQString().sprintf(" - %s", (TQDateTime::currentDateTime().toString(Qt::ISODate)).ascii());
+ TQString comment = i18n("Recorded by TDERadio");
+ size_t l = title.length() + comment.length() + 10;
+ m_ID3Tags = new char[l];
+ char *ctitle = m_ID3Tags;
+ strcpy(ctitle, title.latin1());
+ char *ccomment = m_ID3Tags + strlen(ctitle) + 1;
+ strcpy(ccomment, comment.latin1());
+ id3tag_set_title(m_LAMEFlags, ctitle);
+ id3tag_set_comment(m_LAMEFlags, ccomment);
+ }
+
+ m_MP3Output = fopen(output.ascii(), "wb+");
+ if (!m_MP3Output) {
+ m_errorString += i18n("Cannot open output file %1. ").arg(output);
+ m_error = true;
+ }
+
+ size_t nSamples = m_config.m_EncodeBufferSize / m_config.m_SoundFormat.frameSize();
+ m_MP3BufferSize = nSamples + nSamples / 4 + 7200;
+ m_MP3Buffer = new unsigned char[m_MP3BufferSize];
+
+ m_MP3LBuffer = new short int[nSamples];
+ m_MP3RBuffer = new short int[nSamples];
+
+ if (!m_MP3Buffer || !m_MP3LBuffer || !m_MP3RBuffer) {
+ m_error = true;
+ m_errorString += i18n("Cannot allocate buffers for mp3 encoding. ");
+ }
+ }
+
+ if (m_error) {
+ if (m_LAMEFlags) lame_close(m_LAMEFlags);
+ m_LAMEFlags = NULL;
+ if (m_MP3Output) fclose(m_MP3Output);
+ m_MP3Output = NULL;
+ if (m_MP3Buffer) delete [] m_MP3Buffer;
+ m_MP3Buffer = NULL;
+ m_MP3BufferSize = 0;
+ if (m_ID3Tags) delete [] m_ID3Tags;
+ m_ID3Tags = NULL;
+ if (m_MP3LBuffer) delete[] m_MP3LBuffer;
+ if (m_MP3RBuffer) delete[] m_MP3RBuffer;
+ m_MP3LBuffer = m_MP3RBuffer = NULL;
+ }
+#endif
+ return !m_error;
+}
+
+
+void RecordingEncodingMP3::closeOutput()
+{
+#ifdef HAVE_LAME
+ if (m_LAMEFlags) {
+ if (m_config.m_OutputFormat == RecordingConfig::outputMP3) {
+ int n = lame_encode_flush(m_LAMEFlags,
+ m_MP3Buffer,
+ m_MP3BufferSize);
+ if (n < 0) {
+ m_error = true;
+ m_errorString += i18n("Error %1 while encoding mp3. ").arg(TQString().setNum(n));
+ } else if (n > 0) {
+ int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output);
+ if (r <= 0) {
+ m_error = true;
+ m_errorString += i18n("Error %1 writing output. ").arg(TQString().setNum(r));
+ } else {
+ lame_mp3_tags_fid(m_LAMEFlags, m_MP3Output);
+ }
+ }
+ }
+ if (m_LAMEFlags) lame_close(m_LAMEFlags);
+ m_LAMEFlags = NULL;
+ if (m_MP3Output) fclose(m_MP3Output);
+ m_MP3Output = NULL;
+ m_MP3BufferSize = 0;
+ if (m_MP3Buffer) delete [] m_MP3Buffer;
+ m_MP3Buffer = NULL;
+ if (m_ID3Tags) delete [] m_ID3Tags;
+ m_ID3Tags = NULL;
+ if (m_MP3LBuffer) delete[] m_MP3LBuffer;
+ if (m_MP3RBuffer) delete[] m_MP3RBuffer;
+ m_MP3LBuffer = m_MP3RBuffer = NULL;
+ }
+#endif
+}
diff --git a/plugins/recording/encoder_mp3.h b/plugins/recording/encoder_mp3.h
new file mode 100644
index 0000000..aaa912c
--- /dev/null
+++ b/plugins/recording/encoder_mp3.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ encoder_mp3.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_MP3_H
+#define KRADIO_RECORDING_ENCODER_MP3_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#ifdef HAVE_LAME
+ #include <lame/lame.h>
+#endif
+
+class RecordingEncodingMP3 : public RecordingEncoding
+{
+public:
+ RecordingEncodingMP3(TQObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const TQString &filename);
+ virtual ~RecordingEncodingMP3();
+
+ bool openOutput(const TQString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+#ifdef HAVE_LAME
+ unsigned char *m_MP3Buffer;
+ size_t m_MP3BufferSize;
+ FILE *m_MP3Output;
+ char *m_ID3Tags;
+ lame_global_flags *m_LAMEFlags;
+ short int *m_MP3LBuffer,
+ *m_MP3RBuffer;
+#endif
+};
+
+
+
+#endif
diff --git a/plugins/recording/encoder_ogg.cpp b/plugins/recording/encoder_ogg.cpp
new file mode 100644
index 0000000..ca093b9
--- /dev/null
+++ b/plugins/recording/encoder_ogg.cpp
@@ -0,0 +1,250 @@
+/***************************************************************************
+ encoder_ogg.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "encoder_ogg.h"
+
+#include <tdelocale.h>
+#include <stdlib.h>
+
+RecordingEncodingOgg::RecordingEncodingOgg(TQObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const TQString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename)
+#ifdef HAVE_OGG
+ ,
+ m_OggOutput(NULL),
+ m_OggExportBuffer(NULL),
+ m_OggExportBufferSize(0)
+#endif
+{
+ m_config.m_OutputFormat = RecordingConfig::outputOGG;
+ m_config.m_SoundFormat.m_Encoding = "ogg";
+ openOutput(filename);
+}
+
+
+RecordingEncodingOgg::~RecordingEncodingOgg()
+{
+ closeOutput();
+}
+
+void RecordingEncodingOgg::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+
+#ifdef HAVE_OGG
+ SoundFormat &sf = m_config.m_SoundFormat;
+ ogg_page ogg_pg;
+ ogg_packet ogg_pkt;
+
+ size_t samples = buffer_size / sf.frameSize();
+
+ // buffer[channel][sample], normalized to -1..0..+1
+ float **buffer = vorbis_analysis_buffer(&m_VorbisDSP, (samples < 512 ? 512 : samples));
+
+ sf.convertSamplesToFloat(_buffer, buffer, samples);
+
+ /* Tell the library how many samples (per channel) we wrote
+ into the supplied buffer */
+ vorbis_analysis_wrote(&m_VorbisDSP, samples);
+
+ /* While we can get enough data from the library to analyse, one
+ block at a time... */
+
+ bool eos = false;
+ while(!m_error && !eos && vorbis_analysis_blockout(&m_VorbisDSP, &m_VorbisBlock) == 1) {
+
+ /* Do the main analysis, creating a packet */
+ vorbis_analysis(&m_VorbisBlock, NULL);
+ vorbis_bitrate_addblock(&m_VorbisBlock);
+
+ while(!m_error && vorbis_bitrate_flushpacket(&m_VorbisDSP, &ogg_pkt)) {
+ /* Add packet to bitstream */
+ ogg_stream_packetin(&m_OggStream,&ogg_pkt);
+
+ /* If we've gone over a page boundary, we can do actual output,
+ so do so (for however many pages are available) */
+
+ while(!m_error && !eos) {
+ int result = ogg_stream_pageout(&m_OggStream, &ogg_pg);
+ if (!result) break;
+
+ int n = fwrite(ogg_pg.header, 1, ogg_pg.header_len, m_OggOutput);
+ n += fwrite(ogg_pg.body, 1, ogg_pg.body_len, m_OggOutput);
+
+ m_encodedSize += n;
+
+ if (n != (ogg_pg.header_len + ogg_pg.body_len)) {
+ m_error = true;
+ m_errorString += i18n("Failed writing data to ogg/vorbis output stream. ");
+ break;
+ } else {
+
+ if (m_OggExportBufferSize < export_buffer_size + n) {
+ m_OggExportBuffer = (char*)realloc(m_OggExportBuffer, m_OggExportBufferSize + 2 * n);
+ m_OggExportBufferSize += 2 * n;
+ }
+
+ memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.header, ogg_pg.header_len);
+ export_buffer_size += ogg_pg.header_len;
+ memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.body, ogg_pg.body_len);
+ export_buffer_size += ogg_pg.body_len;
+
+ }
+ if (ogg_page_eos(&ogg_pg))
+ eos = 1;
+ }
+ }
+ }
+
+ export_buffer = m_OggExportBuffer;
+#endif
+}
+
+
+#ifdef HAVE_OGG
+static void vorbis_comment_add_tag_new(vorbis_comment *vc, const TQString &tag, const TQString &value)
+{
+ char *stag = strdup(tag.ascii());
+ char *svalue = strdup(value.utf8());
+ vorbis_comment_add_tag(vc, stag, svalue);
+ delete stag;
+ delete svalue;
+}
+#endif
+
+bool RecordingEncodingOgg::openOutput(const TQString &output)
+{
+#ifdef HAVE_OGG
+ m_OggOutput = fopen(output.ascii(), "wb+");
+ if (!m_OggOutput) {
+ m_errorString += i18n("Cannot open Ogg/Vorbis output file %1. ").arg(output);
+ m_error = true;
+ }
+
+ m_OggExportBuffer = (char*)malloc(m_OggExportBufferSize = 65536); // start with a 64k buffer
+
+
+ /* Have vorbisenc choose a mode for us */
+ vorbis_info_init(&m_VorbisInfo);
+
+ SoundFormat &sf = m_config.m_SoundFormat;
+ if (vorbis_encode_setup_vbr(&m_VorbisInfo, sf.m_Channels, sf.m_SampleRate, m_config.m_oggQuality)) {
+ m_error = true;
+ m_errorString = i18n("Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n");
+ vorbis_info_clear(&m_VorbisInfo);
+ return false;
+ }
+
+ /* Turn off management entirely (if it was turned on). */
+ vorbis_encode_ctl(&m_VorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL);
+ vorbis_encode_setup_init(&m_VorbisInfo);
+
+ /* Now, set up the analysis engine, stream encoder, and other
+ preparation before the encoding begins.
+ */
+
+ vorbis_analysis_init(&m_VorbisDSP, &m_VorbisInfo);
+ vorbis_block_init(&m_VorbisDSP, &m_VorbisBlock);
+
+ ogg_stream_init (&m_OggStream, m_SoundStreamID.getID());
+
+ /* Now, build the three header packets and send through to the stream
+ output stage (but defer actual file output until the main encode loop) */
+
+ ogg_packet header_main;
+ ogg_packet header_comments;
+ ogg_packet header_codebooks;
+
+ /* Build the packets */
+ vorbis_comment vc;
+ vorbis_comment_init (&vc);
+ vorbis_comment_add_tag_new(&vc, "creator", "TDERadio" VERSION);
+ vorbis_comment_add_tag_new(&vc, "title", m_RadioStation->longName().utf8());
+ vorbis_comment_add_tag_new(&vc, "date", TQDateTime::currentDateTime().toString(Qt::ISODate));
+
+ vorbis_analysis_headerout(&m_VorbisDSP, &vc,
+ &header_main, &header_comments, &header_codebooks);
+
+ /* And stream them out */
+ ogg_stream_packetin(&m_OggStream, &header_main);
+ ogg_stream_packetin(&m_OggStream, &header_comments);
+ ogg_stream_packetin(&m_OggStream, &header_codebooks);
+
+ int result;
+ ogg_page ogg_page;
+ while((result = ogg_stream_flush(&m_OggStream, &ogg_page))) {
+
+ if (!result) break;
+
+ int n = fwrite(ogg_page.header, 1, ogg_page.header_len, m_OggOutput);
+ n += fwrite(ogg_page.body, 1, ogg_page.body_len, m_OggOutput);
+
+ if(n != ogg_page.header_len + ogg_page.body_len) {
+ m_error = true;
+ m_errorString += i18n("Failed writing Ogg/Vorbis header to output stream\n");
+ break;
+ }
+ }
+
+ vorbis_comment_clear (&vc);
+
+ if (m_error) {
+ if (m_OggOutput) fclose (m_OggOutput);
+ m_OggOutput = NULL;
+ free(m_OggExportBuffer);
+ m_OggExportBuffer = NULL;
+ m_OggExportBufferSize = 0;
+
+ ogg_stream_clear(&m_OggStream);
+ vorbis_block_clear(&m_VorbisBlock);
+ vorbis_dsp_clear(&m_VorbisDSP);
+ vorbis_info_clear(&m_VorbisInfo);
+ }
+
+ return !m_error;
+#endif
+}
+
+
+void RecordingEncodingOgg::closeOutput()
+{
+#ifdef HAVE_OGG
+ if (m_OggOutput) {
+
+ char *tmp_buf = NULL;
+ size_t tmp_size = 0;
+ // flush buffer
+ encode(tmp_buf, tmp_size, tmp_buf, tmp_size);
+
+ fclose(m_OggOutput);
+ m_OggOutput = NULL;
+
+ free(m_OggExportBuffer);
+ m_OggExportBuffer = NULL;
+ m_OggExportBufferSize = 0;
+
+ ogg_stream_clear(&m_OggStream);
+ vorbis_block_clear(&m_VorbisBlock);
+ vorbis_dsp_clear(&m_VorbisDSP);
+ vorbis_info_clear(&m_VorbisInfo);
+ }
+#endif
+}
+
+
diff --git a/plugins/recording/encoder_ogg.h b/plugins/recording/encoder_ogg.h
new file mode 100644
index 0000000..586c96e
--- /dev/null
+++ b/plugins/recording/encoder_ogg.h
@@ -0,0 +1,55 @@
+/***************************************************************************
+ encoder_ogg.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_OGG_H
+#define KRADIO_RECORDING_ENCODER_OGG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#ifdef HAVE_OGG
+ #include <vorbis/vorbisenc.h>
+#endif
+
+class RecordingEncodingOgg : public RecordingEncoding
+{
+public:
+ RecordingEncodingOgg(TQObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const TQString &filename);
+ virtual ~RecordingEncodingOgg();
+
+ bool openOutput(const TQString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+#ifdef HAVE_OGG
+ FILE *m_OggOutput;
+ char *m_OggExportBuffer;
+ size_t m_OggExportBufferSize;
+ ogg_stream_state m_OggStream;
+ vorbis_dsp_state m_VorbisDSP;
+ vorbis_block m_VorbisBlock;
+ vorbis_info m_VorbisInfo;
+#endif
+};
+
+
+#endif
diff --git a/plugins/recording/encoder_pcm.cpp b/plugins/recording/encoder_pcm.cpp
new file mode 100644
index 0000000..24a8ab6
--- /dev/null
+++ b/plugins/recording/encoder_pcm.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+ encoder_pcm.cpp
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "encoder_pcm.h"
+
+
+#include <tdelocale.h>
+
+RecordingEncodingPCM::RecordingEncodingPCM(TQObject *parent, SoundStreamID ssid,
+ const RecordingConfig &cfg, const RadioStation *rs,
+ const TQString &filename)
+ : RecordingEncoding(parent, ssid, cfg, rs, filename),
+ m_output(NULL)
+{
+ m_config.m_SoundFormat.m_Encoding = "raw";
+ openOutput(filename);
+}
+
+
+RecordingEncodingPCM::~RecordingEncodingPCM()
+{
+ closeOutput();
+}
+
+
+
+void RecordingEncodingPCM::encode(const char *buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size)
+{
+ if (m_error)
+ return;
+ m_encodedSize += buffer_size;
+
+ export_buffer = const_cast<char*>(buffer);
+ export_buffer_size = buffer_size;
+ int err = sf_write_raw(m_output, const_cast<char*>(buffer), buffer_size);
+
+ if (err != (int)buffer_size) {
+ m_error = true;
+ m_errorString += i18n("Error %1 writing output. ").arg(TQString().setNum(err));
+ }
+}
+
+
+bool RecordingEncodingPCM::openOutput(const TQString &output)
+{
+ SF_INFO sinfo;
+ m_config.getSoundFileInfo(sinfo, false);
+ m_output = sf_open(output.ascii(), SFM_WRITE, &sinfo);
+
+ if (!m_output) {
+ m_error = true;
+ m_errorString += i18n("Cannot open output file %1. ").arg(output);
+ }
+ return !m_error;
+}
+
+
+void RecordingEncodingPCM::closeOutput()
+{
+ if (m_output) sf_close (m_output);
+ m_output = NULL;
+}
+
+
diff --git a/plugins/recording/encoder_pcm.h b/plugins/recording/encoder_pcm.h
new file mode 100644
index 0000000..40e6cf4
--- /dev/null
+++ b/plugins/recording/encoder_pcm.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ encoder_pcm.h
+ -------------------
+ begin : Sat Aug 20 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_ENCODER_PCM_H
+#define KRADIO_RECORDING_ENCODER_PCM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "encoder.h"
+
+#include <sndfile.h>
+
+class RecordingEncodingPCM : public RecordingEncoding
+{
+public:
+ RecordingEncodingPCM(TQObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const TQString &filename);
+ virtual ~RecordingEncodingPCM();
+
+ bool openOutput(const TQString &outputFile);
+ void closeOutput();
+
+protected:
+ void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size);
+
+
+ SNDFILE *m_output;
+};
+
+
+#endif
diff --git a/plugins/recording/icons/Makefile.am b/plugins/recording/icons/Makefile.am
new file mode 100644
index 0000000..974b96b
--- /dev/null
+++ b/plugins/recording/icons/Makefile.am
@@ -0,0 +1,2 @@
+icons_ICON = AUTO
+iconsdir = $(datadir)/icons
diff --git a/plugins/recording/icons/hi16-action-tderadio_record.png b/plugins/recording/icons/hi16-action-tderadio_record.png
new file mode 100644
index 0000000..ff75485
--- /dev/null
+++ b/plugins/recording/icons/hi16-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi16-app-tderadio_plus_rec.png b/plugins/recording/icons/hi16-app-tderadio_plus_rec.png
new file mode 100644
index 0000000..deea3dc
--- /dev/null
+++ b/plugins/recording/icons/hi16-app-tderadio_plus_rec.png
Binary files differ
diff --git a/plugins/recording/icons/hi22-action-tderadio_record.png b/plugins/recording/icons/hi22-action-tderadio_record.png
new file mode 100644
index 0000000..9706942
--- /dev/null
+++ b/plugins/recording/icons/hi22-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi22-app-tderadio_plus_rec.png b/plugins/recording/icons/hi22-app-tderadio_plus_rec.png
new file mode 100644
index 0000000..50697cc
--- /dev/null
+++ b/plugins/recording/icons/hi22-app-tderadio_plus_rec.png
Binary files differ
diff --git a/plugins/recording/icons/hi256-action-tderadio_record.png b/plugins/recording/icons/hi256-action-tderadio_record.png
new file mode 100644
index 0000000..a372627
--- /dev/null
+++ b/plugins/recording/icons/hi256-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi32-action-tderadio_record.png b/plugins/recording/icons/hi32-action-tderadio_record.png
new file mode 100644
index 0000000..8cb0ebd
--- /dev/null
+++ b/plugins/recording/icons/hi32-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi32-app-tderadio_plus_rec.png b/plugins/recording/icons/hi32-app-tderadio_plus_rec.png
new file mode 100644
index 0000000..91d46f4
--- /dev/null
+++ b/plugins/recording/icons/hi32-app-tderadio_plus_rec.png
Binary files differ
diff --git a/plugins/recording/icons/hi48-action-tderadio_record.png b/plugins/recording/icons/hi48-action-tderadio_record.png
new file mode 100644
index 0000000..69aca1d
--- /dev/null
+++ b/plugins/recording/icons/hi48-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi48-app-tderadio_plus_rec.png b/plugins/recording/icons/hi48-app-tderadio_plus_rec.png
new file mode 100644
index 0000000..975335c
--- /dev/null
+++ b/plugins/recording/icons/hi48-app-tderadio_plus_rec.png
Binary files differ
diff --git a/plugins/recording/icons/hi64-action-tderadio_record.png b/plugins/recording/icons/hi64-action-tderadio_record.png
new file mode 100644
index 0000000..4b2efce
--- /dev/null
+++ b/plugins/recording/icons/hi64-action-tderadio_record.png
Binary files differ
diff --git a/plugins/recording/icons/hi64-app-tderadio_plus_rec.png b/plugins/recording/icons/hi64-app-tderadio_plus_rec.png
new file mode 100644
index 0000000..9decd00
--- /dev/null
+++ b/plugins/recording/icons/hi64-app-tderadio_plus_rec.png
Binary files differ
diff --git a/plugins/recording/po/Makefile.am b/plugins/recording/po/Makefile.am
new file mode 100644
index 0000000..b2533fe
--- /dev/null
+++ b/plugins/recording/po/Makefile.am
@@ -0,0 +1,2 @@
+PACKAGE = tderadio-recording
+POFILES = AUTO
diff --git a/plugins/recording/po/de.po b/plugins/recording/po/de.po
new file mode 100644
index 0000000..0cf82d0
--- /dev/null
+++ b/plugins/recording/po/de.po
@@ -0,0 +1,396 @@
+# translation of de.po to
+# translation of tderadio-recording.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: 2019-12-22 15:33+0000\n"
+"Last-Translator: Chris <xchrisx@uber.space>\n"
+"Language-Team: German <https://mirror.git.trinitydesktop.org/weblate/"
+"projects/applications/tderadio-recording/de/>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 3.9.1\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte, Chris (TDE)"
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de, (Keine Email)"
+
+#: encoder_mp3.cpp:79 encoder_mp3.cpp:189
+msgid "Error %1 while encoding mp3. "
+msgstr "Fehler %1 beim Kodieren des MP3-Streams. "
+
+#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53
+msgid "Error %1 writing output. "
+msgstr "Fehler %1 beim Schreiben der Ausgabedatei. "
+
+#: encoder_mp3.cpp:106
+msgid "Cannot initialize lalibmp3lame. "
+msgstr "Die Funktionsbibliothek libmp3lame kann nicht initialisiert werden. "
+
+#: encoder_mp3.cpp:123
+msgid "Cannot initialize libmp3lame parameters. "
+msgstr ""
+"Die Parameter der Funktionsbibliothek libmp3lame konnten nicht initialisiert "
+"werden. "
+
+#: encoder_mp3.cpp:130
+msgid "Recorded by TDERadio"
+msgstr "Aufzeichnung durch TDERadio"
+
+#: encoder_mp3.cpp:143 encoder_pcm.cpp:66
+msgid "Cannot open output file %1. "
+msgstr "Die Ausgabedatei %1 kann nicht geöffnet werden. "
+
+#: encoder_mp3.cpp:156
+msgid "Cannot allocate buffers for mp3 encoding. "
+msgstr ""
+"Die Puffer für das Kodieren des MP3-Streams konnten nicht angelegt werden. "
+
+#: encoder_ogg.cpp:94
+msgid "Failed writing data to ogg/vorbis output stream. "
+msgstr "Das schreiben der Ogg/Vorbis-Daten schlug fehl. "
+
+#: encoder_ogg.cpp:136
+msgid "Cannot open Ogg/Vorbis output file %1. "
+msgstr "Die Ogg/Vorbis-Ausgabedatei %1 konnte nicht geöffnet werden. "
+
+#: encoder_ogg.cpp:149
+msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"
+msgstr ""
+"Die Initialisierung des Ogg/Vorbis-Modes schlug fehl: Ungültiger Qualitäts-"
+"Parameter\n"
+
+#: encoder_ogg.cpp:200
+msgid "Failed writing Ogg/Vorbis header to output stream\n"
+msgstr "Das Schreiben der Ogg/Vorbis-Kopfdaten der Ausgabedatei schlug fehl\n"
+
+#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179
+msgid "%1 dB"
+msgstr "%1 dB"
+
+#: recording-monitor.cpp:34
+msgid "Recording Monitor"
+msgstr "Aufnahme-Überwachung"
+
+#: recording-monitor.cpp:38 recording.cpp:47
+msgid "TDERadio Recording Monitor"
+msgstr "TDERadio Aufnahme-Überwachung"
+
+#: recording-monitor.cpp:43
+msgid "SoundStream"
+msgstr "Aufnahmedatenstrom"
+
+#: recording-monitor.cpp:45
+msgid "Status"
+msgstr "Status"
+
+#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50
+#: recording-monitor.cpp:52 recording-monitor.cpp:54
+msgid "<undefined>"
+msgstr "<undefiniert>"
+
+#: recording-monitor.cpp:47
+msgid "Recording File"
+msgstr "Aufnahmedatei"
+
+#: recording-monitor.cpp:49
+msgid "File Size"
+msgstr "Dateigröße"
+
+#: recording-monitor.cpp:51
+msgid "Recording Time"
+msgstr "Aufnahmezeit"
+
+#: recording-configuration-ui.ui:359 recording-monitor.cpp:53
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Abtastrate"
+
+#: recording-monitor.cpp:57 recording-monitor.cpp:393 recording-monitor.cpp:396
+msgid "&Record"
+msgstr "&Aufnehmen"
+
+#: recording-monitor.cpp:74 recording-monitor.cpp:118 recording-monitor.cpp:141
+msgid "nothing"
+msgstr "nichts"
+
+#: recording-monitor.cpp:339
+msgid "%1 Byte"
+msgstr "%1 Byte"
+
+#: recording-monitor.cpp:340
+msgid "%1 kB"
+msgstr "%1 kB"
+
+#: recording-monitor.cpp:341
+msgid "%1 MB"
+msgstr "%1 MB"
+
+#: recording-monitor.cpp:342
+msgid "%1 GB"
+msgstr "%1 GB"
+
+#: recording-monitor.cpp:345
+msgid "%1 Hz"
+msgstr "%1 Hz"
+
+#: recording-monitor.cpp:393
+msgid "&Stop Recording"
+msgstr "Aufnahme anhalten"
+
+#: recording.cpp:46 recording.cpp:54
+msgid "TDERadio Recording Plugin"
+msgstr "TDERadio Aufnahme-Plugin"
+
+#: recording.cpp:131 recording.cpp:132
+msgid "Recording"
+msgstr "Aufnahme"
+
+#: recording.cpp:360
+msgid "start capture not handled"
+msgstr "Der Aufnahmestart wurde ignoriert"
+
+#: recording.cpp:367
+msgid "Recording starting"
+msgstr "Die Aufnahme wird gestartet"
+
+#: recording.cpp:369
+msgid "starting encoding thread failed"
+msgstr "Das Starten des Aufnahme-Threads schlug fehl"
+
+#: recording.cpp:451
+msgid "could not read suffient data"
+msgstr "es konnten nicht ausreichend Daten gelesen werden"
+
+#: recording.cpp:482
+msgid ""
+"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 "
+"input bytes"
+msgstr ""
+"Pufferüberlauf des Aufnahmepuffers des Kodierers/Komprimierers (Fehlerhafte "
+"Konfiguration der Puffer?). Es wurden %1 Bytes ignoriert."
+
+#: recording.cpp:544
+msgid "Recording::outputFile: "
+msgstr "Aufnahme::Ausgabedatei: "
+
+#: recording.cpp:594
+msgid "The encoding thread did not finish. It will be killed now."
+msgstr ""
+"Der Kodierungs-Thread beendete sich nicht selber. Er wird jetzt mit roher "
+"Gewalt beendet."
+
+#: recording.cpp:614
+msgid "Recording stopped"
+msgstr "Die Aufnahme wurde beendet"
+
+#: recording.cpp:647
+msgid ""
+"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes"
+msgstr ""
+"Recording::notifySoundStreamData(Kodierte Daten): Die Empfängermodule "
+"übersprangen %1 Bytess"
+
+#: recording-configuration-ui.ui:16
+#, no-c-format
+msgid "RecordingConfigurationUI"
+msgstr "RecordingConfigurationUI"
+
+#: recording-configuration-ui.ui:34
+#, no-c-format
+msgid "Output"
+msgstr "Ausgabe"
+
+#: recording-configuration-ui.ui:138
+#, no-c-format
+msgid "MP3 Quality(0 - high, 9 - low)"
+msgstr "MP3 Qualität(0 - hoch, 9 - niedrig)"
+
+#: recording-configuration-ui.ui:149
+#, no-c-format
+msgid "raw pcm output (.raw)"
+msgstr "reine PCM-Ausgabe (.raw)"
+
+#: recording-configuration-ui.ui:154
+#, no-c-format
+msgid "Microsoft Wave (.wav)"
+msgstr "Microsoft Wave (.wav)"
+
+#: recording-configuration-ui.ui:159
+#, no-c-format
+msgid "Apple/SGI (.aiff)"
+msgstr "Apple/SGI (.aiff)"
+
+#: recording-configuration-ui.ui:164
+#, no-c-format
+msgid "Sun/NeXT (.au)"
+msgstr "Sun/NeXT (.au)"
+
+#: recording-configuration-ui.ui:169
+#, no-c-format
+msgid "MP3 Compressed (.mp3)"
+msgstr "MP3 komprimiert (.mp3)"
+
+#: recording-configuration-ui.ui:174
+#, no-c-format
+msgid "Ogg/Vorbis Compressed (.ogg)"
+msgstr "Ogg/Vorbis komprimiert (.ogg)"
+
+#: recording-configuration-ui.ui:194
+#, no-c-format
+msgid "Recording Directory"
+msgstr "Aufnahme-Verzeichnis"
+
+#: recording-configuration-ui.ui:202
+#, no-c-format
+msgid "File Format"
+msgstr "Dateiformat"
+
+#: recording-configuration-ui.ui:210
+#, no-c-format
+msgid "Ogg Quality(0 - low, 9 - high)"
+msgstr "Ogg Qualität(0 - niedrig, 9 - hoch)"
+
+#: recording-configuration-ui.ui:239
+#, no-c-format
+msgid "I&nput"
+msgstr "Quelle"
+
+#: recording-configuration-ui.ui:276
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#: recording-configuration-ui.ui:281
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#: recording-configuration-ui.ui:286
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#: recording-configuration-ui.ui:291
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#: recording-configuration-ui.ui:311
+#, no-c-format
+msgid "Endianess"
+msgstr "Byte-Reihenfolge"
+
+#: recording-configuration-ui.ui:334
+#, no-c-format
+msgid "Stereo"
+msgstr "Stereo"
+
+#: recording-configuration-ui.ui:339
+#, no-c-format
+msgid "Mono"
+msgstr "Mono"
+
+#: recording-configuration-ui.ui:365
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#: recording-configuration-ui.ui:370
+#, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#: recording-configuration-ui.ui:388
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#: recording-configuration-ui.ui:393
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#: recording-configuration-ui.ui:413
+#, no-c-format
+msgid "Channels"
+msgstr "Kanäle"
+
+#: recording-configuration-ui.ui:421
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Quantisierungs-Bits"
+
+#: recording-configuration-ui.ui:427
+#, no-c-format
+msgid "Signed"
+msgstr "Vorzeichenbehaftet"
+
+#: recording-configuration-ui.ui:432
+#, no-c-format
+msgid "Unsigned"
+msgstr "Vorzeichenlos"
+
+#: recording-configuration-ui.ui:490
+#, no-c-format
+msgid "&Buffers"
+msgstr "&Puffer"
+
+#: recording-configuration-ui.ui:512
+#, no-c-format
+msgid " kB"
+msgstr " kB"
+
+#: recording-configuration-ui.ui:532
+#, no-c-format
+msgid "Encoding Buffer Size"
+msgstr "Kodierungs-Puffergröße"
+
+#: recording-configuration-ui.ui:551
+#, no-c-format
+msgid "Number of Buffers"
+msgstr "Anzahl der Puffer"
+
+#: recording-configuration-ui.ui:580
+#, no-c-format
+msgid "Pre-Recordin&g"
+msgstr "Aufnahme&vorlaufs"
+
+#: recording-configuration-ui.ui:610
+#, no-c-format
+msgid "E&nable"
+msgstr "&Einschalten"
+
+#: recording-configuration-ui.ui:613
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#: recording-configuration-ui.ui:651
+#, no-c-format
+msgid "PreRecording Time"
+msgstr "Dauer des Aufnahmevorlaufs"
+
+#: recording-configuration-ui.ui:662
+#, no-c-format
+msgid " s"
+msgstr " s"
+
+#~ msgid "Waiting for encoding thread to terminate."
+#~ msgstr "Warte auf die Beendigung des Codierungs-Threads."
diff --git a/plugins/recording/po/ru.po b/plugins/recording/po/ru.po
new file mode 100644
index 0000000..86d7b2f
--- /dev/null
+++ b/plugins/recording/po/ru.po
@@ -0,0 +1,391 @@
+# translation of ru.po to
+# translation of tderadio-recording.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: 2006-11-08 12:35+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: encoder_mp3.cpp:79 encoder_mp3.cpp:189
+msgid "Error %1 while encoding mp3. "
+msgstr "При кодировании MP3 произошла ошибка: %1. "
+
+#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53
+msgid "Error %1 writing output. "
+msgstr "Во время записи произошла ошибка: %1"
+
+#: encoder_mp3.cpp:106
+msgid "Cannot initialize lalibmp3lame. "
+msgstr ""
+"Не могу инициализировать lalibmp3lame — необходимо для кодирования в MP3."
+
+#: encoder_mp3.cpp:123
+msgid "Cannot initialize libmp3lame parameters. "
+msgstr ""
+"Не могу инициализировать параметры libmp3lame — необходимо для кодирования в "
+"MP3."
+
+#: encoder_mp3.cpp:130
+msgid "Recorded by TDERadio"
+msgstr "Запись TDERadio"
+
+#: encoder_mp3.cpp:143 encoder_pcm.cpp:66
+msgid "Cannot open output file %1. "
+msgstr "Не могу открыть выходной файл %1. "
+
+#: encoder_mp3.cpp:156
+msgid "Cannot allocate buffers for mp3 encoding. "
+msgstr "Не могу разместить в памяти буферы для кодирования MP3."
+
+#: encoder_ogg.cpp:94
+msgid "Failed writing data to ogg/vorbis output stream. "
+msgstr "Ошибка записи данных в выходной поток ogg/vorbis. "
+
+#: encoder_ogg.cpp:136
+msgid "Cannot open Ogg/Vorbis output file %1. "
+msgstr "Не могу открыть выходной файл Ogg/Vorbis \"%1\". "
+
+#: encoder_ogg.cpp:149
+msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"
+msgstr ""
+"Инициализация режима Ogg/Vorbis не удалась: качество записи указано неверно\n"
+
+#: encoder_ogg.cpp:200
+msgid "Failed writing Ogg/Vorbis header to output stream\n"
+msgstr "Ошибка записи заголовка Ogg/Vorbis в выходной поток\n"
+
+#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179
+msgid "%1 dB"
+msgstr "%1 дБ"
+
+#: recording-monitor.cpp:34
+msgid "Recording Monitor"
+msgstr "Монитор записи"
+
+#: recording-monitor.cpp:38 recording.cpp:47
+msgid "TDERadio Recording Monitor"
+msgstr "Монитор записи для TDERadio"
+
+#: recording-monitor.cpp:43
+msgid "SoundStream"
+msgstr "Источник"
+
+#: recording-monitor.cpp:45
+msgid "Status"
+msgstr "Состояние"
+
+#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50
+#: recording-monitor.cpp:52 recording-monitor.cpp:54
+msgid "<undefined>"
+msgstr "<не определено>"
+
+#: recording-monitor.cpp:47
+msgid "Recording File"
+msgstr "Файл"
+
+#: recording-monitor.cpp:49
+msgid "File Size"
+msgstr "Размер файла"
+
+#: recording-monitor.cpp:51
+msgid "Recording Time"
+msgstr "Длительность записи"
+
+#: recording-configuration-ui.ui:359 recording-monitor.cpp:53
+#, no-c-format
+msgid "Sample Rate"
+msgstr "Частота дискретизации"
+
+#: recording-monitor.cpp:57 recording-monitor.cpp:393 recording-monitor.cpp:396
+msgid "&Record"
+msgstr "&Начать запись"
+
+#: recording-monitor.cpp:74 recording-monitor.cpp:118 recording-monitor.cpp:141
+msgid "nothing"
+msgstr "(нет)"
+
+#: recording-monitor.cpp:339
+msgid "%1 Byte"
+msgstr "%1 байт"
+
+#: recording-monitor.cpp:340
+msgid "%1 kB"
+msgstr "%1 кБ"
+
+#: recording-monitor.cpp:341
+msgid "%1 MB"
+msgstr "%1 МБ"
+
+#: recording-monitor.cpp:342
+msgid "%1 GB"
+msgstr "%1 ГБ"
+
+#: recording-monitor.cpp:345
+msgid "%1 Hz"
+msgstr "%1 Гц"
+
+#: recording-monitor.cpp:393
+msgid "&Stop Recording"
+msgstr "&Остановить запись"
+
+#: recording.cpp:46 recording.cpp:54
+msgid "TDERadio Recording Plugin"
+msgstr "Модуль записи звука для TDERadio"
+
+#: recording.cpp:131 recording.cpp:132
+msgid "Recording"
+msgstr "Запись"
+
+#: recording.cpp:360
+msgid "start capture not handled"
+msgstr ""
+
+#: recording.cpp:367
+msgid "Recording starting"
+msgstr "Запись запущена"
+
+#: recording.cpp:369
+msgid "starting encoding thread failed"
+msgstr "Не смог запустить процесс кодирования"
+
+#: recording.cpp:451
+msgid "could not read suffient data"
+msgstr "Не смог прочесть достаточно данных"
+
+#: recording.cpp:482
+msgid ""
+"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 "
+"input bytes"
+msgstr ""
+"Переполнение на входе кодировщика (вероятно, неправильно настроен буфер). "
+"Пропускаю %1 байт на входе."
+
+#: recording.cpp:544
+msgid "Recording::outputFile: "
+msgstr "Recording::outputFile (выходной файл записи):"
+
+#: recording.cpp:594
+msgid "The encoding thread did not finish. It will be killed now."
+msgstr "Нить кодировщика не завершилась. Процесс будет уничтожен."
+
+#: recording.cpp:614
+#, fuzzy
+msgid "Recording stopped"
+msgstr "Запись заершена"
+
+#: recording.cpp:647
+msgid ""
+"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes"
+msgstr ""
+"Recording::notifySoundStreamData(encoded data): Приёмник пропустил %1 байт"
+
+#: recording-configuration-ui.ui:16
+#, no-c-format
+msgid "RecordingConfigurationUI"
+msgstr "RecordingConfigurationUI"
+
+#: recording-configuration-ui.ui:34
+#, no-c-format
+msgid "Output"
+msgstr "Выход"
+
+#: recording-configuration-ui.ui:138
+#, no-c-format
+msgid "MP3 Quality(0 - high, 9 - low)"
+msgstr "Качество MP3 (0 — высокое, 9 — низкое)"
+
+#: recording-configuration-ui.ui:149
+#, no-c-format
+msgid "raw pcm output (.raw)"
+msgstr "Неформатированный вывод (.raw)"
+
+#: recording-configuration-ui.ui:154
+#, no-c-format
+msgid "Microsoft Wave (.wav)"
+msgstr "Microsoft Wave (.wav)"
+
+#: recording-configuration-ui.ui:159
+#, no-c-format
+msgid "Apple/SGI (.aiff)"
+msgstr "Apple/SGI (.aiff)"
+
+#: recording-configuration-ui.ui:164
+#, no-c-format
+msgid "Sun/NeXT (.au)"
+msgstr "Sun/NeXT (.au)"
+
+#: recording-configuration-ui.ui:169
+#, no-c-format
+msgid "MP3 Compressed (.mp3)"
+msgstr "Сжатый MP3 (.mp3)"
+
+#: recording-configuration-ui.ui:174
+#, no-c-format
+msgid "Ogg/Vorbis Compressed (.ogg)"
+msgstr "Сжатый Ogg Vorbis (.ogg)"
+
+#: recording-configuration-ui.ui:194
+#, no-c-format
+msgid "Recording Directory"
+msgstr "Каталог для сохранения"
+
+#: recording-configuration-ui.ui:202
+#, no-c-format
+msgid "File Format"
+msgstr "Формат файла"
+
+#: recording-configuration-ui.ui:210
+#, no-c-format
+msgid "Ogg Quality(0 - low, 9 - high)"
+msgstr "Качество Ogg (0 — ниже, 9 — выше)"
+
+#: recording-configuration-ui.ui:239
+#, no-c-format
+msgid "I&nput"
+msgstr "В&вод"
+
+#: recording-configuration-ui.ui:276
+#, no-c-format
+msgid "48000"
+msgstr "48000"
+
+#: recording-configuration-ui.ui:281
+#, no-c-format
+msgid "44100"
+msgstr "44100"
+
+#: recording-configuration-ui.ui:286
+#, no-c-format
+msgid "22050"
+msgstr "22050"
+
+#: recording-configuration-ui.ui:291
+#, no-c-format
+msgid "11025"
+msgstr "11025"
+
+#: recording-configuration-ui.ui:311
+#, no-c-format
+msgid "Endianess"
+msgstr "Порядок байтов"
+
+#: recording-configuration-ui.ui:334
+#, no-c-format
+msgid "Stereo"
+msgstr "2 (Стерео)"
+
+#: recording-configuration-ui.ui:339
+#, no-c-format
+msgid "Mono"
+msgstr "1 (Моно)"
+
+#: recording-configuration-ui.ui:365
+#, no-c-format
+msgid "Little Endian"
+msgstr "Little Endian"
+
+#: recording-configuration-ui.ui:370
+#, fuzzy, no-c-format
+msgid "Big Endian"
+msgstr "Big Endian"
+
+#: recording-configuration-ui.ui:388
+#, no-c-format
+msgid "16"
+msgstr "16"
+
+#: recording-configuration-ui.ui:393
+#, no-c-format
+msgid "8"
+msgstr "8"
+
+#: recording-configuration-ui.ui:413
+#, no-c-format
+msgid "Channels"
+msgstr "Число каналов"
+
+#: recording-configuration-ui.ui:421
+#, no-c-format
+msgid "Sample Bits"
+msgstr "Бит на элемент выборки"
+
+#: recording-configuration-ui.ui:427
+#, no-c-format
+msgid "Signed"
+msgstr "Со знаком"
+
+#: recording-configuration-ui.ui:432
+#, no-c-format
+msgid "Unsigned"
+msgstr "Без знака"
+
+#: recording-configuration-ui.ui:490
+#, no-c-format
+msgid "&Buffers"
+msgstr "&Буферы"
+
+#: recording-configuration-ui.ui:512
+#, no-c-format
+msgid " kB"
+msgstr " кБ"
+
+#: recording-configuration-ui.ui:532
+#, no-c-format
+msgid "Encoding Buffer Size"
+msgstr "Размер буфера для записи"
+
+#: recording-configuration-ui.ui:551
+#, no-c-format
+msgid "Number of Buffers"
+msgstr "Количество буферов"
+
+#: recording-configuration-ui.ui:580
+#, no-c-format
+msgid "Pre-Recordin&g"
+msgstr "&Упреждающая запись"
+
+#: recording-configuration-ui.ui:610
+#, no-c-format
+msgid "E&nable"
+msgstr "Включить"
+
+#: recording-configuration-ui.ui:613
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#: recording-configuration-ui.ui:651
+#, no-c-format
+msgid "PreRecording Time"
+msgstr "Упреждение"
+
+#: recording-configuration-ui.ui:662
+#, no-c-format
+msgid " s"
+msgstr " с"
+
+#~ msgid "Waiting for encoding thread to terminate."
+#~ msgstr "Жду завершения нити кодировщика"
diff --git a/plugins/recording/po/tderadio-recording.pot b/plugins/recording/po/tderadio-recording.pot
new file mode 100644
index 0000000..601779c
--- /dev/null
+++ b/plugins/recording/po/tderadio-recording.pot
@@ -0,0 +1,378 @@
+# SOME DESCRIPTIVE TITLE.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+#, ignore-inconsistent
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr ""
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+#, ignore-inconsistent
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr ""
+
+#: encoder_mp3.cpp:79 encoder_mp3.cpp:189
+msgid "Error %1 while encoding mp3. "
+msgstr ""
+
+#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53
+msgid "Error %1 writing output. "
+msgstr ""
+
+#: encoder_mp3.cpp:106
+msgid "Cannot initialize lalibmp3lame. "
+msgstr ""
+
+#: encoder_mp3.cpp:123
+msgid "Cannot initialize libmp3lame parameters. "
+msgstr ""
+
+#: encoder_mp3.cpp:130
+msgid "Recorded by TDERadio"
+msgstr ""
+
+#: encoder_mp3.cpp:143 encoder_pcm.cpp:66
+msgid "Cannot open output file %1. "
+msgstr ""
+
+#: encoder_mp3.cpp:156
+msgid "Cannot allocate buffers for mp3 encoding. "
+msgstr ""
+
+#: encoder_ogg.cpp:94
+msgid "Failed writing data to ogg/vorbis output stream. "
+msgstr ""
+
+#: encoder_ogg.cpp:136
+msgid "Cannot open Ogg/Vorbis output file %1. "
+msgstr ""
+
+#: encoder_ogg.cpp:149
+msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"
+msgstr ""
+
+#: encoder_ogg.cpp:200
+msgid "Failed writing Ogg/Vorbis header to output stream\n"
+msgstr ""
+
+#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179
+msgid "%1 dB"
+msgstr ""
+
+#: recording-monitor.cpp:34
+msgid "Recording Monitor"
+msgstr ""
+
+#: recording-monitor.cpp:38 recording.cpp:47
+msgid "TDERadio Recording Monitor"
+msgstr ""
+
+#: recording-monitor.cpp:43
+msgid "SoundStream"
+msgstr ""
+
+#: recording-monitor.cpp:45
+msgid "Status"
+msgstr ""
+
+#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50
+#: recording-monitor.cpp:52 recording-monitor.cpp:54
+msgid "<undefined>"
+msgstr ""
+
+#: recording-monitor.cpp:47
+msgid "Recording File"
+msgstr ""
+
+#: recording-monitor.cpp:49
+msgid "File Size"
+msgstr ""
+
+#: recording-monitor.cpp:51
+msgid "Recording Time"
+msgstr ""
+
+#: recording-configuration-ui.ui:359 recording-monitor.cpp:53
+#, no-c-format
+msgid "Sample Rate"
+msgstr ""
+
+#: recording-monitor.cpp:57 recording-monitor.cpp:393 recording-monitor.cpp:396
+msgid "&Record"
+msgstr ""
+
+#: recording-monitor.cpp:74 recording-monitor.cpp:118 recording-monitor.cpp:141
+msgid "nothing"
+msgstr ""
+
+#: recording-monitor.cpp:339
+msgid "%1 Byte"
+msgstr ""
+
+#: recording-monitor.cpp:340
+msgid "%1 kB"
+msgstr ""
+
+#: recording-monitor.cpp:341
+msgid "%1 MB"
+msgstr ""
+
+#: recording-monitor.cpp:342
+msgid "%1 GB"
+msgstr ""
+
+#: recording-monitor.cpp:345
+msgid "%1 Hz"
+msgstr ""
+
+#: recording-monitor.cpp:393
+msgid "&Stop Recording"
+msgstr ""
+
+#: recording.cpp:46 recording.cpp:54
+msgid "TDERadio Recording Plugin"
+msgstr ""
+
+#: recording.cpp:131 recording.cpp:132
+msgid "Recording"
+msgstr ""
+
+#: recording.cpp:360
+msgid "start capture not handled"
+msgstr ""
+
+#: recording.cpp:367
+msgid "Recording starting"
+msgstr ""
+
+#: recording.cpp:369
+msgid "starting encoding thread failed"
+msgstr ""
+
+#: recording.cpp:451
+msgid "could not read suffient data"
+msgstr ""
+
+#: recording.cpp:482
+msgid ""
+"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 "
+"input bytes"
+msgstr ""
+
+#: recording.cpp:544
+msgid "Recording::outputFile: "
+msgstr ""
+
+#: recording.cpp:594
+msgid "The encoding thread did not finish. It will be killed now."
+msgstr ""
+
+#: recording.cpp:614
+msgid "Recording stopped"
+msgstr ""
+
+#: recording.cpp:647
+msgid ""
+"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes"
+msgstr ""
+
+#: recording-configuration-ui.ui:16
+#, no-c-format
+msgid "RecordingConfigurationUI"
+msgstr ""
+
+#: recording-configuration-ui.ui:34
+#, no-c-format
+msgid "Output"
+msgstr ""
+
+#: recording-configuration-ui.ui:138
+#, no-c-format
+msgid "MP3 Quality(0 - high, 9 - low)"
+msgstr ""
+
+#: recording-configuration-ui.ui:149
+#, no-c-format
+msgid "raw pcm output (.raw)"
+msgstr ""
+
+#: recording-configuration-ui.ui:154
+#, no-c-format
+msgid "Microsoft Wave (.wav)"
+msgstr ""
+
+#: recording-configuration-ui.ui:159
+#, no-c-format
+msgid "Apple/SGI (.aiff)"
+msgstr ""
+
+#: recording-configuration-ui.ui:164
+#, no-c-format
+msgid "Sun/NeXT (.au)"
+msgstr ""
+
+#: recording-configuration-ui.ui:169
+#, no-c-format
+msgid "MP3 Compressed (.mp3)"
+msgstr ""
+
+#: recording-configuration-ui.ui:174
+#, no-c-format
+msgid "Ogg/Vorbis Compressed (.ogg)"
+msgstr ""
+
+#: recording-configuration-ui.ui:194
+#, no-c-format
+msgid "Recording Directory"
+msgstr ""
+
+#: recording-configuration-ui.ui:202
+#, no-c-format
+msgid "File Format"
+msgstr ""
+
+#: recording-configuration-ui.ui:210
+#, no-c-format
+msgid "Ogg Quality(0 - low, 9 - high)"
+msgstr ""
+
+#: recording-configuration-ui.ui:239
+#, no-c-format
+msgid "I&nput"
+msgstr ""
+
+#: recording-configuration-ui.ui:276
+#, no-c-format
+msgid "48000"
+msgstr ""
+
+#: recording-configuration-ui.ui:281
+#, no-c-format
+msgid "44100"
+msgstr ""
+
+#: recording-configuration-ui.ui:286
+#, no-c-format
+msgid "22050"
+msgstr ""
+
+#: recording-configuration-ui.ui:291
+#, no-c-format
+msgid "11025"
+msgstr ""
+
+#: recording-configuration-ui.ui:311
+#, no-c-format
+msgid "Endianess"
+msgstr ""
+
+#: recording-configuration-ui.ui:334
+#, no-c-format
+msgid "Stereo"
+msgstr ""
+
+#: recording-configuration-ui.ui:339
+#, no-c-format
+msgid "Mono"
+msgstr ""
+
+#: recording-configuration-ui.ui:365
+#, no-c-format
+msgid "Little Endian"
+msgstr ""
+
+#: recording-configuration-ui.ui:370
+#, no-c-format
+msgid "Big Endian"
+msgstr ""
+
+#: recording-configuration-ui.ui:388
+#, no-c-format
+msgid "16"
+msgstr ""
+
+#: recording-configuration-ui.ui:393
+#, no-c-format
+msgid "8"
+msgstr ""
+
+#: recording-configuration-ui.ui:413
+#, no-c-format
+msgid "Channels"
+msgstr ""
+
+#: recording-configuration-ui.ui:421
+#, no-c-format
+msgid "Sample Bits"
+msgstr ""
+
+#: recording-configuration-ui.ui:427
+#, no-c-format
+msgid "Signed"
+msgstr ""
+
+#: recording-configuration-ui.ui:432
+#, no-c-format
+msgid "Unsigned"
+msgstr ""
+
+#: recording-configuration-ui.ui:490
+#, no-c-format
+msgid "&Buffers"
+msgstr ""
+
+#: recording-configuration-ui.ui:512
+#, no-c-format
+msgid " kB"
+msgstr ""
+
+#: recording-configuration-ui.ui:532
+#, no-c-format
+msgid "Encoding Buffer Size"
+msgstr ""
+
+#: recording-configuration-ui.ui:551
+#, no-c-format
+msgid "Number of Buffers"
+msgstr ""
+
+#: recording-configuration-ui.ui:580
+#, no-c-format
+msgid "Pre-Recordin&g"
+msgstr ""
+
+#: recording-configuration-ui.ui:610
+#, no-c-format
+msgid "E&nable"
+msgstr ""
+
+#: recording-configuration-ui.ui:613
+#, no-c-format
+msgid "Alt+N"
+msgstr ""
+
+#: recording-configuration-ui.ui:651
+#, no-c-format
+msgid "PreRecording Time"
+msgstr ""
+
+#: recording-configuration-ui.ui:662
+#, no-c-format
+msgid " s"
+msgstr ""
diff --git a/plugins/recording/reccfg_interfaces.cpp b/plugins/recording/reccfg_interfaces.cpp
new file mode 100644
index 0000000..9cbc9e6
--- /dev/null
+++ b/plugins/recording/reccfg_interfaces.cpp
@@ -0,0 +1,151 @@
+/***************************************************************************
+ reccfg_interfaces.cpp - description
+ -------------------
+ begin : Sun May 01 2005
+ copyright : (C) 2005by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 <linux/soundcard.h>
+#include "reccfg_interfaces.h"
+
+// IRecCfg
+
+IF_IMPL_SENDER ( IRecCfg::notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount),
+ noticeEncoderBufferChanged(BufferSize, BufferCount)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifySoundFormatChanged(const SoundFormat &sf),
+ noticeSoundFormatChanged(sf)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyMP3QualityChanged(int q),
+ noticeMP3QualityChanged(q)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyOggQualityChanged(float q),
+ noticeOggQualityChanged(q)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyRecordingDirectoryChanged(const TQString &dir),
+ noticeRecordingDirectoryChanged(dir)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyOutputFormatChanged(RecordingConfig::OutputFormat of),
+ noticeOutputFormatChanged(of)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyPreRecordingChanged(bool enable, int seconds),
+ noticePreRecordingChanged(enable, seconds)
+ );
+IF_IMPL_SENDER ( IRecCfg::notifyRecordingConfigChanged (const RecordingConfig &cfg),
+ noticeRecordingConfigChanged(cfg)
+ );
+
+// IRecCfgClient
+
+IF_IMPL_SENDER ( IRecCfgClient::sendEncoderBuffer (size_t BufferSize, size_t BufferCount),
+ setEncoderBuffer(BufferSize, BufferCount)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendSoundFormat(const SoundFormat &sf),
+ setSoundFormat(sf)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendMP3Quality(int q),
+ setMP3Quality(q)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendOggQuality(float q),
+ setOggQuality(q)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendRecordingDirectory(const TQString &dir),
+ setRecordingDirectory(dir)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendOutputFormat(RecordingConfig::OutputFormat of),
+ setOutputFormat(of)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendPreRecording(bool enable, int seconds),
+ setPreRecording(enable, seconds)
+ );
+IF_IMPL_SENDER ( IRecCfgClient::sendRecordingConfig(const RecordingConfig &cfg),
+ setRecordingConfig(cfg)
+ );
+
+IF_IMPL_QUERY ( void IRecCfgClient::queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount),
+ getEncoderBuffer(BufferSize, BufferCount),
+
+ );
+
+static SoundFormat defaultSoundFormat;
+IF_IMPL_QUERY ( const SoundFormat &IRecCfgClient::querySoundFormat (),
+ getSoundFormat(),
+ defaultSoundFormat
+ );
+
+IF_IMPL_QUERY ( int IRecCfgClient::queryMP3Quality (),
+ getMP3Quality(),
+ 7
+ );
+
+IF_IMPL_QUERY ( float IRecCfgClient::queryOggQuality (),
+ getOggQuality(),
+ 7
+ );
+
+static TQString defaultRecDir("/tmp");
+IF_IMPL_QUERY ( const TQString &IRecCfgClient::queryRecordingDirectory(),
+ getRecordingDirectory(),
+ defaultRecDir
+ );
+
+IF_IMPL_QUERY ( RecordingConfig::OutputFormat IRecCfgClient::queryOutputFormat(),
+ getOutputFormat(),
+ RecordingConfig::outputWAV
+ );
+
+IF_IMPL_QUERY ( bool IRecCfgClient::queryPreRecording(int &seconds),
+ getPreRecording(seconds),
+ false
+ );
+
+static RecordingConfig defaultRecConfig;
+IF_IMPL_QUERY ( const RecordingConfig &IRecCfgClient::queryRecordingConfig(),
+ getRecordingConfig(),
+ defaultRecConfig
+ );
+
+void IRecCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ size_t bs = 0, bc = 0;
+ queryEncoderBuffer(bs, bc);
+ noticeEncoderBufferChanged(bs, bc);
+ noticeSoundFormatChanged(querySoundFormat());
+ noticeMP3QualityChanged (queryMP3Quality());
+ noticeOggQualityChanged (queryOggQuality());
+ noticeRecordingDirectoryChanged(queryRecordingDirectory());
+ noticeOutputFormatChanged(queryOutputFormat());
+ int s = 0;
+ bool e = queryPreRecording(s);
+ noticePreRecordingChanged(e, s);
+ noticeRecordingConfigChanged(queryRecordingConfig());
+}
+
+
+void IRecCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/)
+{
+ size_t bs = 0, bc = 0;
+ queryEncoderBuffer(bs, bc);
+ noticeEncoderBufferChanged(bs, bc);
+ noticeSoundFormatChanged(querySoundFormat());
+ noticeMP3QualityChanged (queryMP3Quality());
+ noticeOggQualityChanged (queryOggQuality());
+ noticeRecordingDirectoryChanged(queryRecordingDirectory());
+ noticeOutputFormatChanged(queryOutputFormat());
+ int s = 0;
+ bool e = queryPreRecording(s);
+ noticePreRecordingChanged(e, s);
+ noticeRecordingConfigChanged(queryRecordingConfig());
+}
+
+
diff --git a/plugins/recording/reccfg_interfaces.h b/plugins/recording/reccfg_interfaces.h
new file mode 100644
index 0000000..937ca42
--- /dev/null
+++ b/plugins/recording/reccfg_interfaces.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ reccfg_interfaces.h - description
+ -------------------
+ begin : Sun May 01 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECCFG_INTERFACES_H
+#define KRADIO_RECCFG_INTERFACES_H
+
+#include "../../src/include/interfaces.h"
+#include "recording-config.h"
+
+INTERFACE(IRecCfg, IRecCfgClient)
+{
+public:
+ IF_CON_DESTRUCTOR(IRecCfg, -1)
+
+RECEIVERS:
+ IF_RECEIVER( setEncoderBuffer (size_t BufferSize, size_t BufferCount) )
+ IF_RECEIVER( setSoundFormat (const SoundFormat &sf) )
+ IF_RECEIVER( setMP3Quality (int q) )
+ IF_RECEIVER( setOggQuality (float q) )
+ IF_RECEIVER( setRecordingDirectory(const TQString &dir) )
+ IF_RECEIVER( setOutputFormat (RecordingConfig::OutputFormat of) )
+ IF_RECEIVER( setPreRecording (bool enable, int seconds) )
+ IF_RECEIVER( setRecordingConfig (const RecordingConfig &cfg) )
+
+SENDERS:
+ IF_SENDER ( notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount) )
+ IF_SENDER ( notifySoundFormatChanged (const SoundFormat &sf) )
+ IF_SENDER ( notifyMP3QualityChanged (int q) )
+ IF_SENDER ( notifyOggQualityChanged (float q) )
+ IF_SENDER ( notifyRecordingDirectoryChanged(const TQString &dir) )
+ IF_SENDER ( notifyOutputFormatChanged (RecordingConfig::OutputFormat of) )
+ IF_SENDER ( notifyPreRecordingChanged (bool enable, int seconds) )
+ IF_SENDER ( notifyRecordingConfigChanged (const RecordingConfig &cfg) )
+
+ANSWERS:
+ IF_ANSWER ( void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const )
+ IF_ANSWER ( const SoundFormat &getSoundFormat () const )
+ IF_ANSWER ( int getMP3Quality () const )
+ IF_ANSWER ( float getOggQuality () const )
+ IF_ANSWER ( const TQString &getRecordingDirectory() const )
+ IF_ANSWER ( RecordingConfig::OutputFormat getOutputFormat() const )
+ IF_ANSWER ( bool getPreRecording(int &seconds) const )
+ IF_ANSWER ( const RecordingConfig &getRecordingConfig() const )
+};
+
+
+
+INTERFACE(IRecCfgClient, IRecCfg)
+{
+public:
+ IF_CON_DESTRUCTOR(IRecCfgClient, 1)
+
+SENDERS:
+ IF_SENDER ( sendEncoderBuffer (size_t BufferSize, size_t BufferCount) )
+ IF_SENDER ( sendSoundFormat (const SoundFormat &sf) )
+ IF_SENDER ( sendMP3Quality (int q) )
+ IF_SENDER ( sendOggQuality (float q) )
+ IF_SENDER ( sendRecordingDirectory(const TQString &dir) )
+ IF_SENDER ( sendOutputFormat (RecordingConfig::OutputFormat of) )
+ IF_SENDER ( sendPreRecording (bool enable, int seconds) )
+ IF_SENDER ( sendRecordingConfig (const RecordingConfig &cfg) )
+
+RECEIVERS:
+ IF_RECEIVER( noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount) )
+ IF_RECEIVER( noticeSoundFormatChanged (const SoundFormat &sf) )
+ IF_RECEIVER( noticeMP3QualityChanged (int q) )
+ IF_RECEIVER( noticeOggQualityChanged (float q) )
+ IF_RECEIVER( noticeRecordingDirectoryChanged(const TQString &dir) )
+ IF_RECEIVER( noticeOutputFormatChanged (RecordingConfig::OutputFormat of) )
+ IF_RECEIVER( noticePreRecordingChanged (bool enable, int seconds) )
+ IF_RECEIVER( noticeRecordingConfigChanged (const RecordingConfig &cfg) )
+
+QUERIES:
+ IF_QUERY ( void queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount) )
+ IF_QUERY ( const SoundFormat &querySoundFormat () )
+ IF_QUERY ( int queryMP3Quality () )
+ IF_QUERY ( float queryOggQuality () )
+ IF_QUERY ( const TQString &queryRecordingDirectory() )
+ IF_QUERY ( RecordingConfig::OutputFormat queryOutputFormat() )
+ IF_QUERY ( bool queryPreRecording(int &seconds) )
+ IF_QUERY ( const RecordingConfig &queryRecordingConfig() )
+
+RECEIVERS:
+ virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/);
+ virtual void noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/);
+};
+
+#endif
diff --git a/plugins/recording/recording-config.cpp b/plugins/recording/recording-config.cpp
new file mode 100644
index 0000000..2395e28
--- /dev/null
+++ b/plugins/recording/recording-config.cpp
@@ -0,0 +1,215 @@
+/***************************************************************************
+ recording-config.cpp - description
+ -------------------
+ begin : Mi Apr 30 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "recording-config.h"
+
+#include <sndfile.h>
+
+RecordingConfig::RecordingConfig ()
+: m_EncodeBufferSize(256*1024),
+ m_EncodeBufferCount(3),
+ m_mp3Quality(7),
+ m_oggQuality(1.0),
+ m_Directory("/tmp"),
+ m_OutputFormat(outputWAV),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+RecordingConfig::RecordingConfig (const TQString &directory,
+ OutputFormat of,
+ const SoundFormat &sf, int mp3_q, float ogg_q)
+: m_EncodeBufferSize(256*1024),
+ m_EncodeBufferCount(3),
+ m_SoundFormat(sf),
+ m_mp3Quality(mp3_q),
+ m_oggQuality(ogg_q),
+ m_Directory(directory),
+ m_OutputFormat(of),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+
+RecordingConfig::RecordingConfig (const RecordingConfig &c)
+ :
+ m_EncodeBufferSize(c.m_EncodeBufferSize),
+ m_EncodeBufferCount(c.m_EncodeBufferCount),
+ m_SoundFormat(c.m_SoundFormat),
+ m_mp3Quality(c.m_mp3Quality),
+ m_oggQuality(c.m_oggQuality),
+ m_Directory(c.m_Directory),
+ m_OutputFormat(c.m_OutputFormat),
+ m_PreRecordingEnable (false),
+ m_PreRecordingSeconds(10)
+{
+ checkFormatSettings();
+}
+
+
+void RecordingConfig::restoreConfig(TDEConfig *c)
+{
+ m_EncodeBufferSize = c->readNumEntry("encodeBufferSize", 256*1024);
+ m_EncodeBufferCount = c->readNumEntry("encodeBufferCount", 3);
+
+ m_SoundFormat.restoreConfig("", c);
+ m_Directory = c->readEntry("directory", "/tmp");
+ m_mp3Quality = c->readNumEntry("mp3quality", 7);
+ m_oggQuality = c->readDoubleNumEntry("oggquality", 1.0);
+ TQString of = c->readEntry("outputFormat", ".wav");
+
+ if (of == ".wav")
+ m_OutputFormat = outputWAV;
+ else if (of == ".aiff")
+ m_OutputFormat = outputAIFF;
+ else if (of == ".au")
+ m_OutputFormat = outputAU;
+#ifdef HAVE_LAME
+ else if (of == ".mp3")
+ m_OutputFormat = outputMP3;
+#endif
+#ifdef HAVE_OGG
+ else if (of == ".ogg")
+ m_OutputFormat = outputOGG;
+#endif
+ else if (of == ".raw")
+ m_OutputFormat = outputRAW;
+
+ // if there was any unknown format
+ else
+ m_OutputFormat = outputWAV;
+
+ m_PreRecordingEnable = c->readBoolEntry("prerecording-enable", false);
+ m_PreRecordingSeconds = c->readNumEntry("prerecording-seconds", 10);
+
+ checkFormatSettings();
+}
+
+
+void RecordingConfig::saveConfig(TDEConfig *c) const
+{
+ c->writeEntry("encodeBufferSize", m_EncodeBufferSize);
+ c->writeEntry("encodeBufferCount", m_EncodeBufferCount);
+ m_SoundFormat.saveConfig("", c);
+ c->writeEntry("directory", m_Directory);
+ c->writeEntry("mp3quality", m_mp3Quality);
+ c->writeEntry("oggquality", m_oggQuality);
+
+ switch(m_OutputFormat) {
+ case outputWAV: c->writeEntry("outputFormat", ".wav"); break;
+ case outputAIFF: c->writeEntry("outputFormat", ".aiff"); break;
+ case outputAU: c->writeEntry("outputFormat", ".au"); break;
+ case outputMP3: c->writeEntry("outputFormat", ".mp3"); break;
+ case outputOGG: c->writeEntry("outputFormat", ".ogg"); break;
+ case outputRAW: c->writeEntry("outputFormat", ".raw"); break;
+ default: c->writeEntry("outputFormat", ".wav"); break;
+ }
+
+ c->writeEntry("prerecording-enable", m_PreRecordingEnable);
+ c->writeEntry("prerecording-seconds", m_PreRecordingSeconds);
+}
+
+
+void RecordingConfig::getSoundFileInfo(SF_INFO &sinfo, bool input)
+{
+ checkFormatSettings();
+
+ sinfo.samplerate = m_SoundFormat.m_SampleRate;
+ sinfo.channels = m_SoundFormat.m_Channels;
+ sinfo.format = 0;
+ sinfo.seekable = !input;
+
+ // U8 only supported for RAW and WAV
+ if (m_SoundFormat.m_SampleBits == 8) {
+ if ((m_SoundFormat.m_IsSigned &&
+ m_OutputFormat != outputWAV) ||
+ m_OutputFormat == outputAU
+ ) {
+ sinfo.format |= SF_FORMAT_PCM_S8;
+ } else {
+ sinfo.format |= SF_FORMAT_PCM_U8;
+ }
+ }
+ if (m_SoundFormat.m_SampleBits == 16)
+ sinfo.format |= SF_FORMAT_PCM_16;
+
+ if (m_SoundFormat.m_Endianess == LITTLE_ENDIAN)
+ sinfo.format |= SF_ENDIAN_LITTLE;
+ else
+ sinfo.format |= SF_ENDIAN_BIG;
+
+ if (input) {
+ sinfo.format |= SF_FORMAT_RAW;
+ } else {
+ switch (m_OutputFormat) {
+ case outputWAV: sinfo.format |= SF_FORMAT_WAV; break;
+ case outputAIFF: sinfo.format |= SF_FORMAT_AIFF; break;
+ case outputAU: sinfo.format |= SF_FORMAT_AU; break;
+ case outputRAW: sinfo.format |= SF_FORMAT_RAW; break;
+ default: sinfo.format |= SF_FORMAT_WAV; break;
+ }
+ }
+}
+
+
+void RecordingConfig::checkFormatSettings()
+{
+ // correct Endianess and Signs for specific formats
+ switch (m_OutputFormat) {
+ case outputWAV:
+ m_SoundFormat.m_Endianess = LITTLE_ENDIAN;
+ if (m_SoundFormat.m_SampleBits == 8)
+ m_SoundFormat.m_IsSigned = false;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputAIFF:
+ m_SoundFormat.m_Endianess = BIG_ENDIAN;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputAU:
+ m_SoundFormat.m_Endianess = BIG_ENDIAN;
+ m_SoundFormat.m_IsSigned = true;
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ case outputMP3:
+ m_SoundFormat.m_IsSigned = true;
+ m_SoundFormat.m_SampleBits = 16;
+ break;
+ case outputOGG:
+ m_SoundFormat.m_IsSigned = true;
+ m_SoundFormat.m_SampleBits = 16;
+ break;
+ case outputRAW:
+ // libsndfile only supports signed 16 bit samples
+ if (m_SoundFormat.m_SampleBits == 16)
+ m_SoundFormat.m_IsSigned = true;
+ break;
+ default:
+ break;
+ }
+}
+
diff --git a/plugins/recording/recording-config.h b/plugins/recording/recording-config.h
new file mode 100644
index 0000000..ba7ba52
--- /dev/null
+++ b/plugins/recording/recording-config.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+ recording-config.h - description
+ -------------------
+ begin : Mi Apr 30 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_CONFIG_H
+#define KRADIO_RECORDING_CONFIG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundformat.h"
+
+class TDEConfig;
+struct SF_INFO;
+
+class RecordingConfig
+{
+public:
+ enum OutputFormat {
+ outputWAV,
+ outputAIFF,
+ outputAU,
+ outputMP3,
+ outputOGG,
+ outputRAW
+ };
+
+public:
+ RecordingConfig ();
+ RecordingConfig (const TQString &directory,
+ OutputFormat of,
+ const SoundFormat &, int mp3_q, float ogg_q);
+ RecordingConfig (const RecordingConfig &c);
+
+ void restoreConfig(TDEConfig *c);
+ void saveConfig(TDEConfig *c) const;
+
+ void getSoundFileInfo(SF_INFO &info, bool input);
+
+ void checkFormatSettings();
+
+public:
+ size_t m_EncodeBufferSize;
+ size_t m_EncodeBufferCount;
+
+ SoundFormat m_SoundFormat;
+ int m_mp3Quality;
+ float m_oggQuality;
+ TQString m_Directory;
+ OutputFormat m_OutputFormat;
+
+ bool m_PreRecordingEnable;
+ int m_PreRecordingSeconds;
+};
+
+
+
+
+#endif
diff --git a/plugins/recording/recording-configuration-ui.ui b/plugins/recording/recording-configuration-ui.ui
new file mode 100644
index 0000000..99d7e0a
--- /dev/null
+++ b/plugins/recording/recording-configuration-ui.ui
@@ -0,0 +1,726 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>RecordingConfigurationUI</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>RecordingConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>468</width>
+ <height>197</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>RecordingConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>kTabWidget13</cstring>
+ </property>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage_2</cstring>
+ </property>
+ <attribute name="title">
+ <string>Output</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout3_2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQSpinBox">
+ <property name="name">
+ <cstring>editOggQuality</cstring>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>7</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget" row="1" column="2">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>141</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQSpinBox">
+ <property name="name">
+ <cstring>editMP3Quality</cstring>
+ </property>
+ <property name="maxValue">
+ <number>9</number>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>5</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="TQLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>labelMP3Quality</cstring>
+ </property>
+ <property name="text">
+ <string>MP3 Quality(0 - high, 9 - low)</string>
+ </property>
+ </widget>
+ <widget class="KURLRequester" row="3" column="2">
+ <property name="name">
+ <cstring>editDirectory</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="2">
+ <item>
+ <property name="text">
+ <string>raw pcm output (.raw)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Microsoft Wave (.wav)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Apple/SGI (.aiff)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Sun/NeXT (.au)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>MP3 Compressed (.mp3)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Ogg/Vorbis Compressed (.ogg)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editFileFormat</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>lableDirectory</cstring>
+ </property>
+ <property name="text">
+ <string>Recording Directory</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>lableFileFormat</cstring>
+ </property>
+ <property name="text">
+ <string>File Format</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>labelOggQuality</cstring>
+ </property>
+ <property name="text">
+ <string>Ogg Quality(0 - low, 9 - high)</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>I&amp;nput</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout69</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>48000</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>44100</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>22050</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>11025</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editRate</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lableEndianess</cstring>
+ </property>
+ <property name="text">
+ <string>Endianess</string>
+ </property>
+ </widget>
+ <spacer row="3" column="2">
+ <property name="name">
+ <cstring>spacer1_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>Stereo</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Mono</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editChannels</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelRate</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Rate</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Little Endian</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Big Endian</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editEndianess</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>16</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>8</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editBits</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lableChannels</cstring>
+ </property>
+ <property name="text">
+ <string>Channels</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lableBits</cstring>
+ </property>
+ <property name="text">
+ <string>Sample Bits</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="2">
+ <item>
+ <property name="text">
+ <string>Signed</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Unsigned</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>editSign</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <spacer row="2" column="2">
+ <property name="name">
+ <cstring>spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>225</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer131</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage_3</cstring>
+ </property>
+ <attribute name="title">
+ <string>&amp;Buffers</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>editBufferSize</cstring>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>2048</number>
+ </property>
+ <property name="minValue">
+ <number>64</number>
+ </property>
+ <property name="lineStep">
+ <number>16</number>
+ </property>
+ <property name="value">
+ <number>256</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>labelEditBufferSize</cstring>
+ </property>
+ <property name="text">
+ <string>Encoding Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="TQSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>editBufferCount</cstring>
+ </property>
+ <property name="minValue">
+ <number>3</number>
+ </property>
+ <property name="value">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>labelEditBufferCount</cstring>
+ </property>
+ <property name="text">
+ <string>Number of Buffers</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage_4</cstring>
+ </property>
+ <attribute name="title">
+ <string>Pre-Recordin&amp;g</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout68</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>m_checkboxPreRecordingEnable</cstring>
+ </property>
+ <property name="text">
+ <string>E&amp;nable</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>380</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>m_labelPreRecordingTime</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>PreRecording Time</string>
+ </property>
+ </widget>
+ <widget class="TQSpinBox">
+ <property name="name">
+ <cstring>m_spinboxPreRecordingSeconds</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="suffix">
+ <string> s</string>
+ </property>
+ <property name="maxValue">
+ <number>999</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="lineStep">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>10</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer132_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_checkboxPreRecordingEnable</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_spinboxPreRecordingSeconds</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>m_checkboxPreRecordingEnable</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>m_labelPreRecordingTime</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="0"/>
+<includes>
+ <include location="global" impldecl="in implementation">kcombobox.h</include>
+ <include location="global" impldecl="in implementation">klineedit.h</include>
+ <include location="global" impldecl="in implementation">kpushbutton.h</include>
+ <include location="global" impldecl="in implementation">kurlrequester.h</include>
+</includes>
+</UI>
diff --git a/plugins/recording/recording-configuration.cpp b/plugins/recording/recording-configuration.cpp
new file mode 100644
index 0000000..f35f7dd
--- /dev/null
+++ b/plugins/recording/recording-configuration.cpp
@@ -0,0 +1,414 @@
+/***************************************************************************
+ recording-configuration.cpp - description
+ -------------------
+ begin : So Aug 31 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "recording-configuration.h"
+//#include "recording-context.h"
+
+#include <kurlrequester.h>
+#include <kcombobox.h>
+#include <tqspinbox.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+
+#include <ktabwidget.h>
+
+
+RecordingConfiguration::RecordingConfiguration (TQWidget *parent)
+ : RecordingConfigurationUI(parent),
+ m_dirty(true),
+ m_ignore_gui_updates(false)
+{
+ editDirectory->setMode(KFile::Directory | KFile::ExistingOnly);
+
+ TQObject::connect(editFileFormat, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotFormatSelectionChanged()));
+ TQObject::connect(editBits, TQT_SIGNAL(activated(int)),
+ this, TQT_SLOT(slotFormatSelectionChanged()));
+
+ connect(editRate, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editBits, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editSign, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editEndianess, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editChannels, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editFileFormat, TQT_SIGNAL(activated(int)), TQT_SLOT(slotSetDirty()));
+ connect(editMP3Quality, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotSetDirty()));
+ connect(editOggQuality, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotSetDirty()));
+ connect(editDirectory, TQT_SIGNAL(textChanged(const TQString &)), TQT_SLOT(slotSetDirty()));
+ connect(editBufferSize, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotSetDirty()));
+ connect(editBufferCount, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotSetDirty()));
+ connect(m_spinboxPreRecordingSeconds, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(slotSetDirty()));
+ connect(m_checkboxPreRecordingEnable, TQT_SIGNAL(toggled(bool)), TQT_SLOT(slotSetDirty()));
+
+// attention: remove items with higher index first ;-) otherwise indexes are not valid
+#ifndef HAVE_OGG
+ editFileFormat->removeItem(FORMAT_OGG_IDX_ORG);
+ delete editOggQuality;
+ editOggQuality = NULL;
+ delete labelOggQuality;
+ labelOggQuality = NULL;
+#endif
+#ifndef HAVE_LAME
+ editFileFormat->removeItem(FORMAT_MP3_IDX_ORG);
+ delete editMP3Quality;
+ editMP3Quality = NULL;
+ delete labelMP3Quality;
+ labelMP3Quality = NULL;
+#endif
+}
+
+
+RecordingConfiguration::~RecordingConfiguration ()
+{
+}
+
+
+void RecordingConfiguration::setGUIBuffers(const RecordingConfig &c)
+{
+ editBufferSize->setValue(c.m_EncodeBufferSize / 1024);
+ editBufferCount->setValue(c.m_EncodeBufferCount);
+}
+
+void RecordingConfiguration::setGUIDirectories(const RecordingConfig &c)
+{
+ editDirectory->setURL(c.m_Directory);
+}
+
+void RecordingConfiguration::setGUISoundFormat(const RecordingConfig &c)
+{
+ switch (c.m_SoundFormat.m_SampleBits) {
+ case 8 : editBits->setCurrentItem(BITS_8_IDX ); break;
+ case 16: editBits->setCurrentItem(BITS_16_IDX); break;
+ default: editBits->setCurrentItem(BITS_16_IDX);
+ }
+ switch (c.m_SoundFormat.m_Channels) {
+ case 1 : editChannels->setCurrentItem(CHANNELS_MONO_IDX); break;
+ case 2 : editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break;
+ default: editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_IsSigned) {
+ case 0 : editSign->setCurrentItem(SIGN_UNSIGNED_IDX); break;
+ case 1 : editSign->setCurrentItem(SIGN_SIGNED_IDX); break;
+ default: editSign->setCurrentItem(SIGN_SIGNED_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_SampleRate) {
+ case 48000: editRate->setCurrentItem(RATE_48000_IDX); break;
+ case 44100: editRate->setCurrentItem(RATE_44100_IDX); break;
+ case 22050: editRate->setCurrentItem(RATE_22050_IDX); break;
+ case 11025: editRate->setCurrentItem(RATE_11025_IDX); break;
+ default: editRate->setCurrentItem(RATE_44100_IDX); break;
+ }
+ switch (c.m_SoundFormat.m_Endianess) {
+ case BIG_ENDIAN : editEndianess->setCurrentItem(ENDIAN_BIG_IDX); break;
+ case LITTLE_ENDIAN : editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break;
+ default: editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break;
+ }
+}
+
+void RecordingConfiguration::setGUIOutputFormat(const RecordingConfig &c)
+{
+ switch (c.m_OutputFormat) {
+ case RecordingConfig::outputWAV: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break;
+ case RecordingConfig::outputAIFF: editFileFormat->setCurrentItem(FORMAT_AIFF_IDX); break;
+ case RecordingConfig::outputAU: editFileFormat->setCurrentItem(FORMAT_AU_IDX); break;
+ case RecordingConfig::outputRAW: editFileFormat->setCurrentItem(FORMAT_RAW_IDX); break;
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3: editFileFormat->setCurrentItem(FORMAT_MP3_IDX); break;
+#endif
+#ifdef HAVE_OGG
+ case RecordingConfig::outputOGG: editFileFormat->setCurrentItem(FORMAT_OGG_IDX); break;
+#endif
+ default: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break;
+ }
+}
+
+void RecordingConfiguration::setGUIEncoderQuality(const RecordingConfig &c)
+{
+#ifdef HAVE_LAME
+ editMP3Quality->setValue(c.m_mp3Quality);
+#endif
+#ifdef HAVE_OGG
+ editOggQuality->setValue((int)(c.m_oggQuality * 9));
+#endif
+}
+
+
+void RecordingConfiguration::setGUIPreRecording(const RecordingConfig &c)
+{
+ m_spinboxPreRecordingSeconds->setValue(c.m_PreRecordingSeconds);
+ m_checkboxPreRecordingEnable->setChecked(c.m_PreRecordingEnable);
+}
+
+
+void RecordingConfiguration::slotOK()
+{
+ if (m_dirty) {
+ storeConfig();
+ sendRecordingConfig(m_RecordingConfig);
+ m_dirty = false;
+ }
+}
+
+
+void RecordingConfiguration::storeConfig()
+{
+ RecordingConfig &c = m_RecordingConfig;
+
+ c.m_EncodeBufferSize = editBufferSize->value() * 1024;
+ c.m_EncodeBufferCount = editBufferCount->value();
+
+ c.m_Directory = editDirectory->url();
+
+ switch(editRate->currentItem()) {
+ case RATE_48000_IDX: c.m_SoundFormat.m_SampleRate = 48000; break;
+ case RATE_44100_IDX: c.m_SoundFormat.m_SampleRate = 44100; break;
+ case RATE_22050_IDX: c.m_SoundFormat.m_SampleRate = 22050; break;
+ case RATE_11025_IDX: c.m_SoundFormat.m_SampleRate = 11025; break;
+ default: c.m_SoundFormat.m_SampleRate = 44100; break;
+ }
+ switch(editChannels->currentItem()) {
+ case CHANNELS_MONO_IDX: c.m_SoundFormat.m_Channels = 1; break;
+ case CHANNELS_STEREO_IDX: c.m_SoundFormat.m_Channels = 2; break;
+ default: c.m_SoundFormat.m_Channels = 2; break;
+ }
+ switch(editSign->currentItem()) {
+ case SIGN_UNSIGNED_IDX: c.m_SoundFormat.m_IsSigned = false; break;
+ case SIGN_SIGNED_IDX: c.m_SoundFormat.m_IsSigned = true; break;
+ default: c.m_SoundFormat.m_IsSigned = true; break;
+ }
+ switch(editEndianess->currentItem()) {
+ case ENDIAN_LITTLE_IDX: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break;
+ case ENDIAN_BIG_IDX: c.m_SoundFormat.m_Endianess = BIG_ENDIAN; break;
+ default: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break;
+ }
+ switch(editBits->currentItem()) {
+ case BITS_8_IDX: c.m_SoundFormat.m_SampleBits = 8; break;
+ case BITS_16_IDX: c.m_SoundFormat.m_SampleBits = 16; break;
+ default: c.m_SoundFormat.m_SampleBits = 16; break;
+ }
+ switch(editFileFormat->currentItem()) {
+ case FORMAT_WAV_IDX: c.m_OutputFormat = RecordingConfig::outputWAV; break;
+ case FORMAT_AIFF_IDX: c.m_OutputFormat = RecordingConfig::outputAIFF; break;
+ case FORMAT_AU_IDX: c.m_OutputFormat = RecordingConfig::outputAU; break;
+ case FORMAT_RAW_IDX: c.m_OutputFormat = RecordingConfig::outputRAW; break;
+#ifdef HAVE_LAME
+ case FORMAT_MP3_IDX: c.m_OutputFormat = RecordingConfig::outputMP3; break;
+#endif
+#ifdef HAVE_OGG
+ case FORMAT_OGG_IDX: c.m_OutputFormat = RecordingConfig::outputOGG; break;
+#endif
+ default: c.m_OutputFormat = RecordingConfig::outputWAV; break;
+ }
+#ifdef HAVE_LAME
+ c.m_mp3Quality = editMP3Quality->value();
+#endif
+#ifdef HAVE_OGG
+ c.m_oggQuality = ((float)editOggQuality->value()) / 9.0f;
+#endif
+
+ c.m_PreRecordingEnable = m_checkboxPreRecordingEnable->isChecked();
+ c.m_PreRecordingSeconds = m_spinboxPreRecordingSeconds->value();
+
+ c.checkFormatSettings();
+}
+
+
+void RecordingConfiguration::slotCancel()
+{
+ if (m_dirty) {
+ noticeRecordingConfigChanged(m_RecordingConfig);
+ m_dirty = false;
+ }
+}
+
+
+void RecordingConfiguration::slotFormatSelectionChanged()
+{
+ int bitsIDX = editBits->currentItem();
+ int formatIDX = editFileFormat->currentItem();
+
+ int endianTest = 0x04030201;
+ bool littleEndian = ((char*)&endianTest)[0] == 0x01;
+
+#ifdef HAVE_LAME
+ editMP3Quality ->setEnabled(false);
+ labelMP3Quality->setEnabled(false);
+#endif
+#ifdef HAVE_OGG
+ editOggQuality ->setEnabled(false);
+ labelOggQuality->setEnabled(false);
+#endif
+
+ editBits->setEnabled(true);
+
+ if (formatIDX == FORMAT_MP3_IDX) {
+ editBits->setDisabled(true);
+ editBits->setCurrentItem(BITS_16_IDX);
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+#ifdef HAVE_LAME
+ editMP3Quality ->setEnabled(true);
+ labelMP3Quality->setEnabled(true);
+#endif
+ } else if (formatIDX == FORMAT_OGG_IDX) {
+ editBits->setDisabled(true);
+ editBits->setCurrentItem(BITS_16_IDX);
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+#ifdef HAVE_OGG
+ editOggQuality ->setEnabled(true);
+ labelOggQuality->setEnabled(true);
+#endif
+ } else {
+ if (bitsIDX == BITS_8_IDX) {
+ if (formatIDX == FORMAT_RAW_IDX || formatIDX == FORMAT_AIFF_IDX) {
+ editSign->setDisabled(false);
+ } else {
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(formatIDX == FORMAT_WAV_IDX ? SIGN_UNSIGNED_IDX : SIGN_SIGNED_IDX);
+ }
+ } else {
+ editSign->setDisabled(true);
+ editSign->setCurrentItem(SIGN_SIGNED_IDX);
+ }
+ }
+
+ switch (formatIDX) {
+ case FORMAT_RAW_IDX :
+ editEndianess->setDisabled(false);
+ break;
+#ifdef HAVE_LAME
+ case FORMAT_MP3_IDX :
+ editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX);
+ editEndianess->setDisabled(true);
+ break;
+#endif
+#ifdef HAVE_OGG
+ case FORMAT_OGG_IDX :
+ editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX);
+ editEndianess->setDisabled(true);
+ break;
+#endif
+ default:
+ editEndianess->setDisabled(true);
+ if (formatIDX == FORMAT_AIFF_IDX || formatIDX == FORMAT_AU_IDX) {
+ editEndianess->setCurrentItem(ENDIAN_BIG_IDX);
+ } else {
+ editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX);
+ }
+ break;
+ }
+}
+
+
+
+bool RecordingConfiguration::noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_EncodeBufferSize = BufferSize;
+ m_RecordingConfig.m_EncodeBufferCount = BufferCount;
+ setGUIBuffers(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+bool RecordingConfiguration::noticeSoundFormatChanged (const SoundFormat &sf)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_SoundFormat = sf;
+ setGUISoundFormat(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+
+bool RecordingConfiguration::noticeMP3QualityChanged (int q)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_mp3Quality = q;
+ setGUIEncoderQuality(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeOggQualityChanged (float q)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_oggQuality = q;
+ setGUIEncoderQuality(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeRecordingDirectoryChanged(const TQString &dir)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_Directory = dir;
+ setGUIDirectories(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeOutputFormatChanged (RecordingConfig::OutputFormat of)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_OutputFormat = of;
+ setGUIOutputFormat(m_RecordingConfig);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticePreRecordingChanged (bool enable, int seconds)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig.m_PreRecordingEnable = enable;
+ m_RecordingConfig.m_PreRecordingSeconds = seconds;
+ setGUIPreRecording(m_RecordingConfig);
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+bool RecordingConfiguration::noticeRecordingConfigChanged(const RecordingConfig &c)
+{
+ m_ignore_gui_updates = true;
+ m_RecordingConfig = c;
+ setGUIBuffers(c);
+ setGUIDirectories(c);
+ setGUISoundFormat(c);
+ setGUIOutputFormat(c);
+ setGUIEncoderQuality(c);
+ setGUIPreRecording(c);
+ slotFormatSelectionChanged();
+ m_ignore_gui_updates = false;
+ return true;
+}
+
+void RecordingConfiguration::slotSetDirty()
+{
+ if (!m_ignore_gui_updates) {
+ m_dirty = true;
+ }
+}
+
+
+#include "recording-configuration.moc"
diff --git a/plugins/recording/recording-configuration.h b/plugins/recording/recording-configuration.h
new file mode 100644
index 0000000..90c2144
--- /dev/null
+++ b/plugins/recording/recording-configuration.h
@@ -0,0 +1,127 @@
+/***************************************************************************
+ recording-configuration.h - description
+ -------------------
+ begin : So Aug 31 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_CONFIGURATION_H
+#define KRADIO_RECORDING_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/soundformat.h"
+
+#include "recording-config.h"
+#include "reccfg_interfaces.h"
+#include "recording-configuration-ui.h"
+
+#define RATE_48000_IDX 0
+#define RATE_44100_IDX 1
+#define RATE_22050_IDX 2
+#define RATE_11025_IDX 3
+
+#define CHANNELS_STEREO_IDX 0
+#define CHANNELS_MONO_IDX 1
+
+#define SIGN_SIGNED_IDX 0
+#define SIGN_UNSIGNED_IDX 1
+
+#define BITS_16_IDX 0
+#define BITS_8_IDX 1
+
+#define ENDIAN_LITTLE_IDX 0
+#define ENDIAN_BIG_IDX 1
+
+#define FORMAT_RAW_IDX 0
+#define FORMAT_WAV_IDX 1
+#define FORMAT_AIFF_IDX 2
+#define FORMAT_AU_IDX 3
+#define NEXT_IDX1 4
+
+#define FORMAT_MP3_IDX_ORG 4
+#define FORMAT_OGG_IDX_ORG 5
+
+
+#ifdef HAVE_LAME
+ #define FORMAT_MP3_IDX NEXT_IDX1
+ #define NEXT_IDX2 (NEXT_IDX1+1)
+#else
+ #define FORMAT_MP3_IDX (-1)
+ #define NEXT_IDX2 NEXT_IDX1
+#endif
+
+#ifdef HAVE_OGG
+ #define FORMAT_OGG_IDX NEXT_IDX2
+ #define NEXT_IDX3 (NEXT_IDX2+1)
+#else
+ #define FORMAT_OGG_IDX (-1)
+ #define NEXT_IDX3 NEXT_IDX2
+#endif
+
+
+
+
+
+
+class RecordingConfiguration : public RecordingConfigurationUI,
+ public IRecCfgClient
+{
+Q_OBJECT
+
+public :
+ RecordingConfiguration (TQWidget *parent);
+ ~RecordingConfiguration ();
+
+// IRecCfgClient
+
+ bool noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount);
+ bool noticeSoundFormatChanged (const SoundFormat &sf);
+ bool noticeMP3QualityChanged (int q);
+ bool noticeOggQualityChanged (float q);
+ bool noticeRecordingDirectoryChanged(const TQString &dir);
+ bool noticeOutputFormatChanged (RecordingConfig::OutputFormat of);
+ bool noticePreRecordingChanged (bool enable, int seconds);
+ bool noticeRecordingConfigChanged (const RecordingConfig &cfg);
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+ void slotSetDirty();
+
+ void slotFormatSelectionChanged();
+
+protected:
+
+ void storeConfig();
+
+ void setGUIBuffers(const RecordingConfig &c);
+ void setGUIDirectories(const RecordingConfig &c);
+ void setGUISoundFormat(const RecordingConfig &c);
+ void setGUIOutputFormat(const RecordingConfig &c);
+ void setGUIPreRecording(const RecordingConfig &c);
+ void setGUIEncoderQuality(const RecordingConfig &c);
+
+ RecordingConfig m_RecordingConfig;
+
+ bool m_dirty;
+ bool m_ignore_gui_updates;
+};
+
+
+
+
+#endif
diff --git a/plugins/recording/recording-datamonitor.cpp b/plugins/recording/recording-datamonitor.cpp
new file mode 100644
index 0000000..cd8b7e1
--- /dev/null
+++ b/plugins/recording/recording-datamonitor.cpp
@@ -0,0 +1,278 @@
+/***************************************************************************
+ recording-monitor-widget.cpp - description
+ -------------------
+ begin : So Sep 7 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "recording-datamonitor.h"
+//#include "recording-context.h"
+#include <math.h>
+
+#include <tqpainter.h>
+#include <tqimage.h>
+#include <tqpixmap.h>
+#include <kimageeffect.h> // fading, blending, ...
+#include <kpixmapio.h> // fast conversion between TQPixmap/TQImage
+#include <limits.h>
+#include <stdlib.h>
+
+#include <tdelocale.h>
+
+#define CHANNEL_H_MIN 20
+#define BLOCK_W_MIN 10
+#define W_MIN (20 * (BLOCK_W_MIN))
+
+RecordingDataMonitor::RecordingDataMonitor(TQWidget *parent, const char *name)
+ : TQFrame(parent, name),
+ m_channelsMax(NULL),
+ m_channelsAvg(NULL),
+ m_maxValue(INT_MAX),
+ m_channels(0),
+ m_pActiveBlocks(NULL)
+{
+ setFrameStyle(Box | Sunken);
+ setLineWidth(1);
+ setMidLineWidth(1);
+
+ setChannels(2);
+
+ setColors(TQColor(20, 244, 20),
+ TQColor(10, 117, 10));
+
+ setSizePolicy(TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding));
+}
+
+
+RecordingDataMonitor::~RecordingDataMonitor()
+{
+ if (m_channelsMax) delete[] m_channelsMax;
+ if (m_channelsAvg) delete[] m_channelsAvg;
+ if (m_pActiveBlocks) delete[] m_pActiveBlocks;
+}
+
+
+
+// own stuff
+
+void RecordingDataMonitor::setChannels(int n)
+{
+ if (n != m_channels) {
+ if (m_channelsMax) delete[] m_channelsMax;
+ if (m_channelsAvg) delete[] m_channelsAvg;
+ if (m_pActiveBlocks) delete[] m_pActiveBlocks;
+ m_channels = n > 0 ? n : 0;
+ if (m_channels > 0) {
+ m_channelsMax = new int[m_channels];
+ m_channelsAvg = new double[m_channels];
+ m_pActiveBlocks = new int[m_channels];
+ for (int i = 0; i < m_channels; ++i) {
+ m_pActiveBlocks[i] = 0;
+ }
+ } else {
+ m_channelsMax = NULL;
+ m_channelsAvg = NULL;
+ m_pActiveBlocks = NULL;
+ }
+ }
+
+ for (int i = 0; i < m_channels; ++i) {
+ m_channelsMax[i] = 0;
+ m_channelsAvg[i] = 0;
+ }
+ setMinimumSize(TQSize(W_MIN, (m_channels + 1 )* CHANNEL_H_MIN));
+}
+
+
+// QT/KDE ...
+
+void RecordingDataMonitor::drawContents(TQPainter *painter)
+{
+ if (painter)
+ internalDrawContents(*painter, true);
+}
+
+void RecordingDataMonitor::internalDrawContents(TQPainter &painter, bool repaintAll)
+{
+ if (m_channels <= 0) return;
+ TQRect r = contentsRect();
+
+ TQPen activePen (colorGroup().color(TQColorGroup::Text), 1);
+ TQPen inactivePen (colorGroup().color(TQColorGroup::Mid), 1);
+ TQBrush activeBrush = colorGroup().brush(TQColorGroup::Text);
+ TQBrush inactiveBrush = colorGroup().brush(TQColorGroup::Mid);
+ TQBrush yellowBrush(TQColor(255,255,0));
+ TQBrush orangeBrush(TQColor(255,192,0));
+ TQBrush redBrush (TQColor(255,0, 0));
+
+
+ double ranges [5] = { 0.75, 0.83, 0.91, 1.0, 999 };
+ TQBrush *brushes[5] = { &activeBrush, &yellowBrush, &orangeBrush, &redBrush, &redBrush };
+
+ painter.setBrush( isEnabled() ? activeBrush : inactiveBrush);
+
+ int nBlocks = (r.width()-1) / BLOCK_W_MIN;
+ int xoffs = (r.width()-1) % BLOCK_W_MIN;
+ int chHeight = (r.height()-1-CHANNEL_H_MIN) / m_channels;
+ int yoffs = (r.height()-1) % m_channels;
+
+ double min_dB = 20*log10(1 / (double)m_maxValue );
+
+ int x0 = xoffs/2 + r.top();
+ int y = yoffs/2 + r.left();
+ for (int c = 0; c < m_channels; ++c) {
+ int x = x0;
+
+
+ int startBlock = 0;
+ int endBlock = nBlocks - 1;
+ int oldActiveBlocks = m_pActiveBlocks[c];
+
+ double dBMax = isEnabled() ? 20*log10(m_channelsMax[c] / (double)m_maxValue ) : min_dB;
+
+ m_pActiveBlocks[c] = m_channelsMax[c] ? (int)rint(nBlocks * (min_dB - dBMax) / min_dB) : 0;
+
+ if (!repaintAll) {
+ if (oldActiveBlocks > m_pActiveBlocks[c]) {
+ startBlock = m_pActiveBlocks[c];
+ endBlock = oldActiveBlocks - 1;
+ } else {
+ startBlock = oldActiveBlocks;
+ endBlock = m_pActiveBlocks[c]-1;
+ }
+ }
+
+ int range = 0;
+
+ x += BLOCK_W_MIN * startBlock;
+ for (int b = startBlock; b <= endBlock; ++b) {
+ while (b >= nBlocks * ranges[range]) ++range;
+ painter.fillRect(x+1, y+1, BLOCK_W_MIN-1, chHeight-1,
+ b < m_pActiveBlocks[c] ? *brushes[range] : inactiveBrush);
+ x += BLOCK_W_MIN;
+ }
+
+ y += chHeight;
+ }
+
+ if (repaintAll) {
+ TQFont f("Helvetica");
+ painter.setPen (activePen);
+ f.setPixelSize(CHANNEL_H_MIN);
+ painter.setFont(f);
+
+ int maxW = TQFontMetrics(f).width(i18n("%1 dB").arg((int)min_dB));
+ int delta_dB = 5;
+ while (abs((long)min_dB) / delta_dB * maxW * 2 > r.width()) delta_dB *= 2;
+
+ for (int dB = 0; dB >= min_dB; dB -= delta_dB) {
+ TQString txt = i18n("%1 dB").arg(dB);
+ int w = TQFontMetrics(f).width(txt);
+ int x = x0 + (int)(nBlocks * BLOCK_W_MIN * (min_dB - dB) / min_dB) - w;
+ if (x < x0) continue;
+ painter.drawText(x, y + CHANNEL_H_MIN, txt);
+ }
+ }
+}
+
+
+bool RecordingDataMonitor::setColors(const TQColor &activeText,
+ const TQColor &button)
+{
+ m_colorActiveText = activeText;
+ m_colorButton = button;
+
+ TQPalette pl = palette();
+ TQColorGroup cg = pl.inactive();
+
+ TQBrush fg = cg.brush(TQColorGroup::Foreground),
+ btn = cg.brush(TQColorGroup::Button),
+ lgt = cg.brush(TQColorGroup::Light),
+ drk = cg.brush(TQColorGroup::Dark),
+ mid = cg.brush(TQColorGroup::Mid),
+ txt = cg.brush(TQColorGroup::Text),
+ btx = cg.brush(TQColorGroup::BrightText),
+ bas = cg.brush(TQColorGroup::Base),
+ bg = cg.brush(TQColorGroup::Background);
+
+ fg.setColor (m_colorActiveText);
+ btn.setColor(m_colorButton);
+ lgt.setColor(m_colorButton.light(180));
+ drk.setColor(m_colorButton.light( 50));
+ mid.setColor(m_colorButton.light( 75));
+ txt.setColor(m_colorActiveText);
+ btx.setColor(m_colorActiveText);
+ bas.setColor(m_colorButton);
+ bg.setColor (m_colorButton);
+
+ TQColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg);
+ pl.setInactive(ncg);
+ pl.setActive(ncg);
+ setPalette(pl);
+
+ if (parentWidget() && parentWidget()->backgroundPixmap() ){
+ KPixmapIO io;
+ TQImage i = io.convertToImage(*parentWidget()->backgroundPixmap());
+ KImageEffect::fade(i, 0.5, colorGroup().color(TQColorGroup::Dark));
+ setPaletteBackgroundPixmap(io.convertToPixmap(i));
+ setBackgroundOrigin(WindowOrigin);
+ } else {
+ setBackgroundColor(colorGroup().color(TQColorGroup::Button));
+ }
+
+ return true;
+}
+
+
+bool RecordingDataMonitor::noticeSoundStreamData(SoundStreamID /*id*/,
+ const SoundFormat &sf, const char *data, size_t size, size_t &/*consumed_size*/,
+ const SoundMetaData &/*md*/
+)
+{
+ if (!isEnabled())
+ return false;
+ int nSamples = size / sf.frameSize();
+ int sample_size = sf.sampleSize();
+
+ int bias = 0;
+ setChannels(sf.m_Channels);
+ int old_max = m_maxValue;
+ m_maxValue = sf.maxValue();
+ if (!sf.m_IsSigned) {
+ m_maxValue /= 2;
+ bias = -m_maxValue;
+ }
+
+ int c = 0;
+ for (int s = 0; s < nSamples; ++s, ++c, data += sample_size) {
+ if (c >= m_channels) c -= m_channels; // avoid slow c = s % m_channels
+
+ int &m = m_channelsMax[c];
+ int x = abs(sf.convertSampleToInt(data, false) + bias);
+ if (m < x) m = x;
+ m_channelsAvg[c] += x;
+ }
+ for (int i = 0; i < m_channels; ++i)
+ m_channelsAvg[i] /= nSamples;
+
+ TQPainter paint(this);
+ if (m_maxValue != old_max) {
+ repaint(true);
+ } else {
+ internalDrawContents(paint, false);
+ }
+ return true;
+}
+
+
+#include "recording-datamonitor.moc"
diff --git a/plugins/recording/recording-datamonitor.h b/plugins/recording/recording-datamonitor.h
new file mode 100644
index 0000000..2ac493e
--- /dev/null
+++ b/plugins/recording/recording-datamonitor.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ recording-monitor-widget.h - description
+ -------------------
+ begin : So Sep 7 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_DATA_MONITOR
+#define KRADIO_RECORDING_DATA_MONITOR
+
+#include <tqframe.h>
+#include <tqcolor.h>
+
+//#include <tderadio/interfaces/recording-interfaces.h>
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+class RecordingDataMonitor : public TQFrame//,
+ //public ISoundStreamClient
+ //public IRecordingClient
+{
+Q_OBJECT
+
+public:
+ RecordingDataMonitor(TQWidget *parent, const char *name);
+ ~RecordingDataMonitor();
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md);
+
+// QT/KDE ...
+
+protected:
+
+ void drawContents(TQPainter *p);
+ void internalDrawContents(TQPainter &painter, bool repaintAll);
+// own stuff ...
+
+protected:
+
+ void setChannels(int n);
+ bool setColors(const TQColor &activeColor, const TQColor &bkgnd);
+
+// data
+protected:
+
+ int *m_channelsMax; // maximum absolute value recorded on each channel
+ double *m_channelsAvg; // average value recorded on each channel
+ int m_maxValue; // maximum absolute value possible for samples
+ int m_channels;
+
+ TQColor m_colorActiveText, m_colorButton;
+
+ int *m_pActiveBlocks;
+};
+
+#endif
diff --git a/plugins/recording/recording-monitor.cpp b/plugins/recording/recording-monitor.cpp
new file mode 100644
index 0000000..ee1514b
--- /dev/null
+++ b/plugins/recording/recording-monitor.cpp
@@ -0,0 +1,402 @@
+/***************************************************************************
+ recording-monitor.cpp - description
+ -------------------
+ begin : Mo Sep 1 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "recording-monitor.h"
+#include "recording-datamonitor.h"
+#include "../../src/include/aboutwidget.h"
+
+#include <tqlabel.h>
+#include <tqpushbutton.h>
+#include <tqlayout.h>
+#include <tqcheckbox.h>
+#include <kcombobox.h>
+
+#include <tdelocale.h>
+#include <tdeconfig.h>
+#include <tdeaboutdata.h>
+
+RecordingMonitor::RecordingMonitor(const TQString &name)
+ : TQWidget(NULL, name.ascii()),
+ WidgetPluginBase(name, i18n("Recording Monitor")),
+ m_recording(false),
+ m_defaultStreamDescription(TQString())
+{
+ setCaption(i18n("TDERadio Recording Monitor"));
+
+ TQVBoxLayout *l = new TQVBoxLayout(this, 10, 4);
+ TQGridLayout *l0 = new TQGridLayout(l, 6, 2);
+
+ l0->addWidget( new TQLabel(i18n("SoundStream"), this), 0, 0);
+ l0->addWidget(m_comboSoundStreamSelector = new KComboBox( this), 0, 1);
+ l0->addWidget( new TQLabel(i18n("Status"), this), 1, 0);
+ l0->addWidget(m_labelStatus = new TQLabel(i18n("<undefined>"), this), 1, 1);
+ l0->addWidget( new TQLabel(i18n("Recording File"), this), 2, 0);
+ l0->addWidget(m_labelFileName = new TQLabel(i18n("<undefined>"), this), 2, 1);
+ l0->addWidget( new TQLabel(i18n("File Size"), this), 3, 0);
+ l0->addWidget(m_labelSize = new TQLabel(i18n("<undefined>"), this), 3, 1);
+ l0->addWidget( new TQLabel(i18n("Recording Time"), this), 4, 0);
+ l0->addWidget(m_labelTime = new TQLabel(i18n("<undefined>"), this), 4, 1);
+ l0->addWidget( new TQLabel(i18n("Sample Rate"), this), 5, 0);
+ l0->addWidget(m_labelRate = new TQLabel(i18n("<undefined>"), this), 5, 1);
+
+ TQPushButton *close = new TQPushButton(i18n("&Close"), this);
+ m_btnStartStop = new TQPushButton(i18n("&Record"), this);
+ TQObject::connect(close, TQT_SIGNAL(clicked()), this, TQT_SLOT(hide()));
+ TQObject::connect(m_btnStartStop, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotStartStopRecording()));
+
+ m_dataMonitor = new RecordingDataMonitor(this, NULL);
+ m_dataMonitor->setEnabled(false);
+
+ TQHBoxLayout *hl0 = new TQHBoxLayout(l);
+ hl0->addWidget(m_dataMonitor);
+
+ TQHBoxLayout *hl2 = new TQHBoxLayout(l);
+ hl2->addItem(new TQSpacerItem(10, 1));
+ hl2->addWidget(close);
+ hl2->addWidget(m_btnStartStop);
+ hl2->addItem(new TQSpacerItem(10, 1));
+
+
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ TQObject::connect(m_comboSoundStreamSelector, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotStreamSelected(int)));
+
+ updateRecordingButton();
+}
+
+
+RecordingMonitor::~RecordingMonitor()
+{
+}
+
+// WidgetPluginBase
+
+void RecordingMonitor::saveState (TDEConfig *config) const
+{
+ config->setGroup(TQString("recordingmonitor-") + name());
+
+ WidgetPluginBase::saveState(config);
+}
+
+
+void RecordingMonitor::restoreState (TDEConfig *config)
+{
+ config->setGroup(TQString("recordingmonitor-") + name());
+
+ WidgetPluginBase::restoreState(config, false);
+}
+
+
+bool RecordingMonitor::connectI(Interface *i)
+{
+ bool a = ISoundStreamClient::connectI(i);
+ bool b = WidgetPluginBase::connectI(i);
+ return a || b;
+}
+
+bool RecordingMonitor::disconnectI(Interface *i)
+{
+ bool a = ISoundStreamClient::disconnectI(i);
+ bool b = WidgetPluginBase::disconnectI(i);
+ if (a) {
+ m_comboSoundStreamSelector->clear();
+ m_SoundStreamID2idx.clear();
+ m_idx2SoundStreamID.clear();
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ }
+ return a || b;
+}
+
+
+void RecordingMonitor::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_notifySoundStreamCreated(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamChanged(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_sendStartRecordingWithFormat(this);
+ s->register4_sendStopRecording(this);
+
+ TQMap<TQString, SoundStreamID> tmp;
+ queryEnumerateSoundStreams(tmp);
+
+ m_comboSoundStreamSelector->clear();
+ m_SoundStreamID2idx.clear();
+ m_idx2SoundStreamID.clear();
+ m_comboSoundStreamSelector->insertItem(i18n("nothing"));
+ TQMapConstIterator<TQString, SoundStreamID> end = tmp.end();
+ for (TQMapConstIterator<TQString, SoundStreamID> it = tmp.begin(); it != end; ++it) {
+ int idx = m_comboSoundStreamSelector->count();
+ m_comboSoundStreamSelector->insertItem(it.key());
+ m_idx2SoundStreamID[idx] = *it;
+ m_SoundStreamID2idx[*it] = idx;
+ }
+ }
+}
+
+ConfigPageInfo RecordingMonitor::createConfigurationPage()
+{
+ return ConfigPageInfo();
+}
+
+AboutPageInfo RecordingMonitor::createAboutPage()
+{
+/* TDEAboutData aboutData("tderadio",
+ NULL,
+ NULL,
+ I18N_NOOP("Recording Monitor Plugin for TDERadio"),
+ TDEAboutData::License_GPL,
+ "(c) 2002-2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/tderadio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new TDERadioAboutWidget(aboutData, TDERadioAboutWidget::AbtTabbed),
+ i18n("Recording Monitor"),
+ i18n("Recording Monitor Plugin"),
+ "goto"
+ );
+*/
+ return AboutPageInfo();
+}
+
+
+void RecordingMonitor::show()
+{
+ WidgetPluginBase::pShow();
+ TQWidget::show();
+}
+
+
+void RecordingMonitor::showOnOrgDesktop()
+{
+ WidgetPluginBase::pShowOnOrgDesktop();
+ //TQWidget::show();
+}
+
+void RecordingMonitor::hide()
+{
+ WidgetPluginBase::pHide();
+ TQWidget::hide();
+}
+
+
+void RecordingMonitor::showEvent(TQShowEvent *e)
+{
+ TQWidget::showEvent(e);
+ WidgetPluginBase::pShowEvent(e);
+ //m_comboSoundStreamSelector->setCurrentItem(1);
+ //slotStreamSelected(1);
+}
+
+
+void RecordingMonitor::hideEvent(TQHideEvent *e)
+{
+ TQWidget::hideEvent(e);
+ WidgetPluginBase::pHideEvent(e);
+ m_comboSoundStreamSelector->setCurrentItem(0);
+ slotStreamSelected(0);
+}
+
+
+void RecordingMonitor::slotStartStopRecording()
+{
+ if (m_currentStream.isValid()) {
+ if (m_recording) {
+ sendStopRecording(m_currentStream);
+ } else {
+ sendStartRecording(m_currentStream);
+ }
+ }
+ updateRecordingButton();
+}
+
+
+bool RecordingMonitor::noticeSoundStreamCreated(SoundStreamID id)
+{
+ TQString tmp = TQString();
+ querySoundStreamDescription(id, tmp);
+
+ int idx = m_comboSoundStreamSelector->count();
+ m_comboSoundStreamSelector->insertItem(tmp);
+ m_idx2SoundStreamID[idx] = id;
+ m_SoundStreamID2idx[id] = idx;
+
+ if (tmp == m_defaultStreamDescription) {
+ m_comboSoundStreamSelector->setCurrentItem(idx);
+ slotStreamSelected(idx);
+ }
+ return true;
+}
+
+
+bool RecordingMonitor::noticeSoundStreamClosed(SoundStreamID id)
+{
+ if (m_SoundStreamID2idx.contains(id)) {
+ int idx = m_SoundStreamID2idx[id];
+ m_idx2SoundStreamID.clear();
+ m_SoundStreamID2idx.remove(id);
+ TQMapIterator<SoundStreamID, int> end = m_SoundStreamID2idx.end();
+ for (TQMapIterator<SoundStreamID, int> it = m_SoundStreamID2idx.begin(); it != end; ++it) {
+ if (*it > idx) {
+ (*it)--;
+ }
+ m_idx2SoundStreamID[*it] = it.key();
+ }
+ m_comboSoundStreamSelector->removeItem(idx);
+ slotStreamSelected(m_comboSoundStreamSelector->currentItem());
+ return true;
+ }
+ return false;
+}
+
+
+bool RecordingMonitor::noticeSoundStreamChanged(SoundStreamID id)
+{
+ if (m_SoundStreamID2idx.contains(id)) {
+ int idx = m_SoundStreamID2idx[id];
+ TQString tmp = TQString();
+ querySoundStreamDescription(id, tmp);
+ m_comboSoundStreamSelector->changeItem(tmp, idx);
+ if (idx == m_comboSoundStreamSelector->currentItem()) {
+ m_defaultStreamDescription = tmp;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool RecordingMonitor::startRecordingWithFormat(SoundStreamID id, const SoundFormat &/*sf*/, SoundFormat &/*real_format*/)
+{
+ if (id == m_currentStream) {
+ m_recording = true;
+ updateRecordingButton();
+ }
+ return false;
+}
+
+bool RecordingMonitor::stopRecording(SoundStreamID id)
+{
+ if (id == m_currentStream) {
+ m_recording = false;
+ updateRecordingButton();
+ }
+ return false;
+}
+
+bool RecordingMonitor::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+)
+{
+ if (m_idx2SoundStreamID[m_comboSoundStreamSelector->currentItem()] == id) {
+
+ m_labelFileName->setText(md.url().url());
+
+ double B = (double)md.position() + (double)size;
+
+ double s = md.relativeTimestamp();
+
+ int m = (int)(s / 60); s -= 60 * m;
+ int h = m / 60; m %= 60;
+ int d = h / 24; h %= 24;
+ TQString time;
+ if (d) {
+ time.sprintf("%dd - %02d:%02d:%05.2f", d, h, m, s);
+ } else {
+ time.sprintf("%02d:%02d:%05.2f", h, m, s);
+ }
+ m_labelTime->setText(time);
+
+ if (sf.m_Encoding == "raw") {
+ m_dataMonitor->setEnabled(true);
+ m_dataMonitor->noticeSoundStreamData(id, sf, data, size, consumed_size, md);
+ } else {
+ m_dataMonitor->setEnabled(false);
+ }
+
+ double kB = B / 1024;
+ double MB = kB / 1024;
+ double GB = MB / 1024;
+ TQString str_size;
+ str_size = i18n("%1 Byte").arg(TDEGlobal::locale()->formatNumber((int)B, 0));
+ if (kB > 1) str_size = i18n("%1 kB").arg(TDEGlobal::locale()->formatNumber(kB, 3));
+ if (MB > 1) str_size = i18n("%1 MB").arg(TDEGlobal::locale()->formatNumber(MB, 3));
+ if (GB > 1) str_size = i18n("%1 GB").arg(TDEGlobal::locale()->formatNumber(GB, 3));
+ m_labelSize->setText(str_size);
+
+ m_labelRate->setText(i18n("%1 Hz").arg(sf.m_SampleRate));
+ return true;
+ }
+ return false;
+}
+
+
+void RecordingMonitor::slotStreamSelected(int idx)
+{
+ SoundStreamID old_id = m_currentStream;
+ if (old_id.isValid()) {
+ sendStopCapture(old_id);
+ }
+
+ SoundStreamID id = m_idx2SoundStreamID.contains(idx) ? m_idx2SoundStreamID[idx] : SoundStreamID::InvalidID;
+ if (id.isValid()) {
+
+ m_defaultStreamDescription = m_comboSoundStreamSelector->text(idx);
+
+ SoundFormat sf;
+ sendStartCaptureWithFormat(id, sf, sf);
+ m_dataMonitor ->setEnabled(true);
+ m_labelSize ->setEnabled(true);
+ m_labelSize ->setEnabled(true);
+ m_labelTime ->setEnabled(true);
+ m_labelRate ->setEnabled(true);
+ m_labelFileName ->setEnabled(true);
+ m_labelStatus ->setEnabled(true);
+ } else {
+ m_dataMonitor ->setEnabled(false);
+ m_labelSize ->setEnabled(false);
+ m_labelSize ->setEnabled(false);
+ m_labelTime ->setEnabled(false);
+ m_labelRate ->setEnabled(false);
+ m_labelFileName ->setEnabled(false);
+ m_labelStatus ->setEnabled(false);
+ }
+ m_currentStream = id;
+ m_recording = false;
+ SoundFormat sf;
+ queryIsRecordingRunning(m_currentStream, m_recording, sf);
+ updateRecordingButton();
+}
+
+
+void RecordingMonitor::updateRecordingButton()
+{
+ if (m_currentStream.isValid()) {
+ m_btnStartStop->setText(!m_recording ? i18n("&Record") : i18n("&Stop Recording"));
+ m_btnStartStop->setEnabled(true);
+ } else {
+ m_btnStartStop->setText(i18n("&Record"));
+ m_btnStartStop->setEnabled(false);
+ }
+}
+
+
+#include "recording-monitor.moc"
diff --git a/plugins/recording/recording-monitor.h b/plugins/recording/recording-monitor.h
new file mode 100644
index 0000000..b2a8890
--- /dev/null
+++ b/plugins/recording/recording-monitor.h
@@ -0,0 +1,125 @@
+/***************************************************************************
+ recording-monitor.h - description
+ -------------------
+ begin : Mo Sep 1 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_MONITOR_H
+#define KRADIO_RECORDING_MONITOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqwidget.h>
+
+#include "../../src/include/widgetplugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+//#include <tderadio/interfaces/recording-interfaces.h>
+
+
+class TQLabel;
+class TQPushButton;
+class TQCheckBox;
+class RecordingDataMonitor;
+class KComboBox;
+
+class RecordingMonitor : public TQWidget,
+ public WidgetPluginBase,
+ public ISoundStreamClient
+ //public IRecordingClient
+{
+Q_OBJECT
+
+public:
+
+ RecordingMonitor(const TQString &name);
+ virtual ~RecordingMonitor();
+
+ const TQString &name() const { return PluginBase::name(); }
+ TQString &name() { return PluginBase::name(); }
+
+ virtual TQString pluginClassName() const { return "RecordingMonitor"; }
+
+ // WidgetPluginBase
+
+public:
+ virtual void saveState (TDEConfig *) const;
+ virtual void restoreState (TDEConfig *);
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // IRecordingClient
+
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool noticeSoundStreamCreated(SoundStreamID id);
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+ bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format);
+ bool stopRecording(SoundStreamID id);
+
+ bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md);
+
+public slots:
+
+ void toggleShown() { WidgetPluginBase::pToggleShown(); }
+ void showOnOrgDesktop();
+ void show();
+ void hide();
+
+ void slotStartStopRecording();
+
+ void slotStreamSelected(int idx);
+
+protected:
+
+ virtual void updateRecordingButton();
+
+ virtual void showEvent(TQShowEvent *);
+ virtual void hideEvent(TQHideEvent *);
+
+ const TQWidget *getWidget() const { return this; }
+ TQWidget *getWidget() { return this; }
+
+
+protected:
+
+ TQLabel *m_labelSize;
+ TQLabel *m_labelTime;
+ TQLabel *m_labelRate;
+ TQLabel *m_labelFileName;
+ TQLabel *m_labelStatus;
+ TQPushButton *m_btnStartStop;
+
+ KComboBox *m_comboSoundStreamSelector;
+ TQMap<SoundStreamID, int> m_SoundStreamID2idx;
+ TQMap<int, SoundStreamID> m_idx2SoundStreamID;
+
+ SoundStreamID m_currentStream;
+ RecordingDataMonitor *m_dataMonitor;
+
+ bool m_recording;
+ TQString m_defaultStreamDescription;
+};
+
+
+
+
+#endif
diff --git a/plugins/recording/recording.cpp b/plugins/recording/recording.cpp
new file mode 100644
index 0000000..2f1ce05
--- /dev/null
+++ b/plugins/recording/recording.cpp
@@ -0,0 +1,731 @@
+/***************************************************************************
+ recording.cpp - description
+ -------------------
+ begin : Mi Aug 27 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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 "../../src/include/radiostation.h"
+#include "../../src/include/errorlog-interfaces.h"
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/fileringbuffer.h"
+#include "../../src/include/utils.h"
+
+#include "recording.h"
+#include "recording-configuration.h"
+#include "soundstreamevent.h"
+#include "recording-monitor.h"
+#include "encoder_mp3.h"
+#include "encoder_ogg.h"
+#include "encoder_pcm.h"
+
+#include <tqevent.h>
+#include <tqapplication.h>
+#include <tqregexp.h>
+
+#include <tdeconfig.h>
+#include <tdeversion.h>
+
+#include <tdeaboutdata.h>
+
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS2(
+ Recording, "tderadio-recording", i18n("TDERadio Recording Plugin"),
+ RecordingMonitor, i18n("TDERadio Recording Monitor")
+);
+
+///////////////////////////////////////////////////////////////////////
+
+Recording::Recording(const TQString &name)
+ : TQObject(NULL, NULL),
+ PluginBase(name, i18n("TDERadio Recording Plugin")),
+ m_config()
+{
+}
+
+
+Recording::~Recording()
+{
+ TQMapIterator<SoundStreamID, RecordingEncoding*> it = m_EncodingThreads.begin();
+ TQMapIterator<SoundStreamID, RecordingEncoding*> end = m_EncodingThreads.end();
+ for (; it != end; ++it) {
+ sendStopRecording(it.key());
+ }
+}
+
+
+bool Recording::connectI(Interface *i)
+{
+ bool a = IRecCfg::connectI(i);
+ bool b = PluginBase::connectI(i);
+ bool c = ISoundStreamClient::connectI(i);
+ return a || b || c;
+}
+
+
+bool Recording::disconnectI(Interface *i)
+{
+ bool a = IRecCfg::disconnectI(i);
+ bool b = PluginBase::disconnectI(i);
+ bool c = ISoundStreamClient::disconnectI(i);
+ return a || b || c;
+}
+
+
+void Recording::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendStartPlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_sendStartRecording(this);
+ s->register4_sendStartRecordingWithFormat(this);
+ s->register4_notifySoundStreamData(this);
+ s->register4_sendStopRecording(this);
+ s->register4_queryIsRecordingRunning(this);
+ s->register4_querySoundStreamDescription(this);
+ s->register4_querySoundStreamRadioStation(this);
+ s->register4_queryEnumerateSoundStreams(this);
+ s->register4_notifySoundStreamChanged(this);
+ s->register4_notifySoundStreamClosed(this);
+ }
+}
+
+// PluginBase
+
+void Recording::saveState (TDEConfig *c) const
+{
+ c->setGroup(TQString("recording-") + PluginBase::name());
+ m_config.saveConfig(c);
+}
+
+
+void Recording::restoreState (TDEConfig *c)
+{
+ c->setGroup(TQString("recording-") + PluginBase::name());
+ RecordingConfig cfg;
+ cfg.restoreConfig(c);
+ setRecordingConfig(cfg);
+ //notifyRecordingConfigChanged(m_config);
+}
+
+
+ConfigPageInfo Recording::createConfigurationPage()
+{
+ RecordingConfiguration *c = new RecordingConfiguration(NULL);
+ connectI(c);
+ return ConfigPageInfo(c,
+ i18n("Recording"),
+ i18n("Recording"),
+ "tderadio_record");
+}
+
+
+AboutPageInfo Recording::createAboutPage()
+{
+/* TDEAboutData aboutData("tderadio",
+ NULL,
+ NULL,
+ I18N_NOOP("Recording Monitor for TDERadio"),
+ TDEAboutData::License_GPL,
+ "(c) 2002-2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/tderadio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new TDERadioAboutWidget(aboutData, TDERadioAboutWidget::AbtTabbed),
+ i18n("Recording"),
+ i18n("Recording Plugin"),
+ "tderadio_record"
+ );*/
+ return AboutPageInfo();
+}
+
+
+// IRecCfg
+
+bool Recording::setEncoderBuffer (size_t BufferSize, size_t BufferCount)
+{
+ if (m_config.m_EncodeBufferSize != BufferSize ||
+ m_config.m_EncodeBufferCount != BufferCount)
+ {
+ m_config.m_EncodeBufferSize = BufferSize;
+ m_config.m_EncodeBufferCount = BufferCount;
+ notifyEncoderBufferChanged(BufferSize, BufferCount);
+ }
+ return true;
+}
+
+bool Recording::setSoundFormat (const SoundFormat &sf)
+{
+ if (m_config.m_SoundFormat != sf) {
+ m_config.m_SoundFormat = sf;
+ notifySoundFormatChanged(sf);
+ }
+ return true;
+}
+
+bool Recording::setMP3Quality (int q)
+{
+ if (m_config.m_mp3Quality != q) {
+ m_config.m_mp3Quality = q;
+ notifyMP3QualityChanged(q);
+ }
+ return true;
+}
+
+bool Recording::setOggQuality (float q)
+{
+ if (m_config.m_oggQuality != q) {
+ m_config.m_oggQuality = q;
+ notifyOggQualityChanged(q);
+ }
+ return true;
+}
+
+bool Recording::setRecordingDirectory(const TQString &dir)
+{
+ if (m_config.m_Directory != dir) {
+ m_config.m_Directory = dir;
+ notifyRecordingDirectoryChanged(dir);
+ }
+ return true;
+}
+
+bool Recording::setOutputFormat (RecordingConfig::OutputFormat of)
+{
+ if (m_config.m_OutputFormat != of) {
+ m_config.m_OutputFormat = of;
+ notifyOutputFormatChanged(of);
+ }
+ return true;
+}
+
+bool Recording::setPreRecording (bool enable, int seconds)
+{
+ if (m_config.m_PreRecordingEnable != enable || m_config.m_PreRecordingSeconds != seconds) {
+ m_config.m_PreRecordingEnable = enable;
+ m_config.m_PreRecordingSeconds = seconds;
+
+ if (enable) {
+ for (TQMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) {
+ if (*it != NULL) {
+ delete *it;
+ }
+ *it = new FileRingBuffer(m_config.m_Directory + "/tderadio-prerecord-"+TQString::number(it.key().getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ SoundFormat sf = m_config.m_SoundFormat;
+ sendStartCaptureWithFormat(it.key(), sf, sf, false);
+ }
+ }
+ else {
+ for (TQMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) {
+ if (*it != NULL) {
+ sendStopCapture(it.key());
+ delete *it;
+ }
+ }
+ m_PreRecordingBuffers.clear();
+ }
+
+ notifyPreRecordingChanged(enable, seconds);
+ }
+ return true;
+}
+
+void Recording::getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const
+{
+ BufferSize = m_config.m_EncodeBufferSize;
+ BufferCount = m_config.m_EncodeBufferCount;
+}
+
+const SoundFormat &Recording::getSoundFormat () const
+{
+ return m_config.m_SoundFormat;
+}
+
+int Recording::getMP3Quality () const
+{
+ return m_config.m_mp3Quality;
+}
+
+float Recording::getOggQuality () const
+{
+ return m_config.m_oggQuality;
+}
+
+const TQString &Recording::getRecordingDirectory() const
+{
+ return m_config.m_Directory;
+}
+
+RecordingConfig::OutputFormat Recording::getOutputFormat() const
+{
+ return m_config.m_OutputFormat;
+}
+
+bool Recording::getPreRecording(int &seconds) const
+{
+ seconds = m_config.m_PreRecordingSeconds;
+ return m_config.m_PreRecordingEnable;
+}
+
+const RecordingConfig &Recording::getRecordingConfig() const
+{
+ return m_config;
+}
+
+bool Recording::setRecordingConfig(const RecordingConfig &c)
+{
+ setEncoderBuffer (c.m_EncodeBufferSize, c.m_EncodeBufferCount);
+ setSoundFormat (c.m_SoundFormat);
+ setMP3Quality (c.m_mp3Quality);
+ setOggQuality (c.m_oggQuality);
+ setRecordingDirectory(c.m_Directory);
+ setOutputFormat (c.m_OutputFormat);
+ setPreRecording (c.m_PreRecordingEnable, c.m_PreRecordingSeconds);
+
+ m_config = c;
+
+ notifyRecordingConfigChanged(m_config);
+
+ return true;
+}
+
+
+// ISoundStreamClient
+bool Recording::startPlayback(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id))
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers[id] = NULL;
+ if (m_config.m_PreRecordingEnable) {
+ m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/tderadio-prerecord-"+TQString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ SoundFormat sf = m_config.m_SoundFormat;
+ sendStartCaptureWithFormat(id, sf, sf, false);
+ }
+ return false;
+}
+
+bool Recording::stopPlayback(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id])
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ sendStopCapture(id);
+ }
+ return false;
+}
+
+bool Recording::startRecording(SoundStreamID id)
+{
+
+/* FileRingBuffer *test = new FileRingBuffer("/tmp/ringbuffertest", 2048);
+ char buffer1[1024];
+ char buffer2[1024];
+ char buffer3[1024];
+ for (int i = 0; i < 1024; ++i) {
+ buffer1[i] = 'a';
+ buffer2[i] = 'b';
+ buffer3[i] = 'c';
+ }
+ test->addData(buffer1, 1024);
+ test->addData(buffer2, 1024);
+ test->removeData(1024);
+ test->addData(buffer3, 1024);
+*/
+
+ SoundFormat realFormat = m_config.m_SoundFormat;
+ return sendStartRecordingWithFormat(id, realFormat, realFormat);
+}
+
+bool Recording::startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format)
+{
+ if (!sendStartCaptureWithFormat(id, sf, real_format, /* force_format = */ true)) {
+ logError(i18n("start capture not handled"));
+ return false;
+ }
+
+ RecordingConfig cfg = m_config;
+ cfg.m_SoundFormat = real_format;
+
+ logInfo(i18n("Recording starting"));
+ if (!startEncoder(id, cfg)) {
+ logError(i18n("starting encoding thread failed"));
+ sendStopCapture(id);
+ return false;
+ }
+
+ return true;
+}
+
+
+bool Recording::stopRecording(SoundStreamID id)
+{
+ if (m_EncodingThreads.contains(id)) {
+ sendStopCapture(id);
+ if (m_config.m_PreRecordingEnable) {
+ if (!m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id] != NULL) {
+ delete m_PreRecordingBuffers[id];
+ }
+ bool b = false;
+ queryIsPlaybackRunning(id, b);
+ if (b) {
+ m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/tderadio-prerecord-"+TQString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize());
+ } else {
+ m_PreRecordingBuffers[id] = NULL;
+ }
+ }
+ }
+ stopEncoder(id);
+ return true;
+ }
+ return false;
+}
+
+
+
+bool Recording::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &/*sf*/, const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+)
+{
+ if (m_PreRecordingBuffers.contains(id) && m_PreRecordingBuffers[id] != NULL) {
+
+ FileRingBuffer &fbuf = *m_PreRecordingBuffers[id];
+ if (fbuf.getFreeSize() < size) {
+ fbuf.removeData(size - fbuf.getFreeSize());
+ }
+ size_t n = fbuf.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min(consumed_size, n);
+// if (n != size) {
+// logDebug("recording packet: was not written completely to tmp buf");
+// }
+
+// //BEGIN DEBUG
+// char tmp[4096];
+// for (unsigned int i = 0; i < sizeof(tmp); ++i) { tmp[i] = 0; }
+// if (fbuf.getFreeSize() < sizeof(tmp)) {
+// fbuf.removeData(sizeof(tmp) - fbuf.getFreeSize());
+// }
+// fbuf.addData((char*)tmp, sizeof(tmp));
+// //END DEBUG
+
+ if (m_EncodingThreads.contains(id)) {
+
+ //logDebug("recording packet: " + TQString::number(size));
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("noticeSoundStreamData thread = " + TQString::number((long long)thread, 16));
+
+ size_t remSize = fbuf.getFillSize();
+
+ while (remSize > 0) {
+ size_t bufferSize = remSize;
+ char *buf = thread->lockInputBuffer(bufferSize);
+ if (!buf) {
+ // Encoder buffer is full and bigger than remaining data
+ break;
+ }
+ if (bufferSize > remSize) {
+ bufferSize = remSize;
+ }
+ if (fbuf.takeData(buf, bufferSize) != bufferSize) {
+ logError(i18n("could not read suffient data"));
+ }
+
+ thread->unlockInputBuffer(bufferSize, md);
+ remSize -= bufferSize;
+ }
+
+ if (remSize == 0) {
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ }
+ }
+
+ return true;
+ }
+
+ else if (m_EncodingThreads.contains(id)) {
+
+ //logDebug("recording packet: " + TQString::number(size));
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("noticeSoundStreamData thread = " + TQString::number((long long)thread, 16));
+
+ size_t remSize = size;
+ const char *remData = data;
+
+ while (remSize > 0) {
+ size_t bufferSize = remSize;
+ char *buf = thread->lockInputBuffer(bufferSize);
+ if (!buf) {
+ logWarning(i18n("Encoder input buffer overflow (buffer configuration problem?). Skipped %1 input bytes").arg(TQString::number(remSize)));
+ break;
+ }
+ if (bufferSize > remSize) {
+ bufferSize = remSize;
+ }
+ memcpy(buf, remData, bufferSize);
+
+ thread->unlockInputBuffer(bufferSize, md);
+ remSize -= bufferSize;
+ remData += bufferSize;
+ }
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? size - remSize : min(consumed_size, size - remSize);
+
+ return true;
+ }
+ return false;
+}
+
+
+
+
+bool Recording::startEncoder(SoundStreamID ssid, const RecordingConfig &cfg)
+{
+ if (m_EncodingThreads.contains(ssid))
+ return false;
+
+ SoundStreamID encID = createNewSoundStream(ssid, false);
+ m_RawStreams2EncodedStreams[ssid] = encID;
+ m_EncodedStreams2RawStreams[encID] = ssid;
+
+ TQString ext = ".wav";
+ switch (m_config.m_OutputFormat) {
+ case RecordingConfig::outputWAV: ext = ".wav"; break;
+ case RecordingConfig::outputAIFF: ext = ".aiff"; break;
+ case RecordingConfig::outputAU: ext = ".au"; break;
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3: ext = ".mp3"; break;
+#endif
+#ifdef HAVE_LAME
+ case RecordingConfig::outputOGG: ext = ".ogg"; break;
+#endif
+ case RecordingConfig::outputRAW: ext = ".raw"; break;
+ default: ext = ".wav"; break;
+ }
+ const RadioStation *rs = NULL;
+ querySoundStreamRadioStation(ssid, rs);
+ TQString station = rs ? rs->name() + "-" : "";
+ station.replace(TQRegExp("[/*?]"), "_");
+
+ TQDate date = TQDate::currentDate();
+ TQTime time = TQTime::currentTime();
+ TQString sdate;
+
+ sdate.sprintf("%d.%d.%d.%d.%d",date.year(),date.month(),date.day(),time.hour(),time.minute());
+
+ TQString output = m_config.m_Directory
+ + "/tderadio-recording-"
+ + station
+ + sdate
+ + ext;
+
+ logInfo(i18n("Recording::outputFile: ") + output);
+
+ RecordingEncoding *thread = NULL;
+ switch (m_config.m_OutputFormat) {
+#ifdef HAVE_LAME
+ case RecordingConfig::outputMP3:
+ thread = new RecordingEncodingMP3(this, ssid, cfg, rs, output);
+ break;
+#endif
+#ifdef HAVE_OGG
+ case RecordingConfig::outputOGG:
+ thread = new RecordingEncodingOgg(this, ssid, cfg, rs, output);
+ break;
+#endif
+ default:
+ thread = new RecordingEncodingPCM(this, ssid, cfg, rs, output);
+ }
+
+ //m_encodingThread->openOutput(output, rs);
+
+ if (thread->error()) {
+ //m_context.setError();
+ logError(thread->errorString());
+ } else {
+ thread->start();
+ }
+ // store thread even if it has indicated an error
+ m_EncodingThreads[ssid] = thread;
+
+ //logDebug("startEncoder thread = " + TQString::number((long long)thread, 16));
+
+ notifySoundStreamCreated(encID);
+ return !thread->error();
+}
+
+
+void Recording::stopEncoder(SoundStreamID id)
+{
+ if (m_EncodingThreads.contains(id)) {
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ thread->setDone();
+
+ //logDebug("stopEncoder thread = " + TQString::number((long long)thread, 16));
+ //logDebug("stopEncoder thread error = " + TQString::number(thread->error(), 16));
+
+ // FIXME: set a timer and do waiting "in background"
+ if (!thread->wait(5000)) {
+ //m_context.setError();
+ logError(i18n("The encoding thread did not finish. It will be killed now."));
+ thread->terminate();
+ thread->wait();
+ } else {
+ if (thread->error()) {
+ //m_context.setError();
+ logError(thread->errorString());
+ } else {
+ //TQ_UINT64 size = thread->encodedSize();
+ //m_context.setEncodedSize(low, high);
+ //notifyRecordingContextChanged(m_context);
+ }
+ }
+ delete thread;
+ m_EncodingThreads.remove(id);
+ SoundStreamID encID = m_RawStreams2EncodedStreams[id];
+ m_EncodedStreams2RawStreams.remove(encID);
+ m_RawStreams2EncodedStreams.remove(id);
+ sendStopPlayback(encID);
+ closeSoundStream(encID);
+ logInfo(i18n("Recording stopped"));
+ }
+}
+
+
+bool Recording::event(TQEvent *_e)
+{
+ if (SoundStreamEvent::isSoundStreamEvent(_e)) {
+ SoundStreamEvent *e = static_cast<SoundStreamEvent*>(_e);
+ SoundStreamID id = e->getSoundStreamID();
+
+ if (m_EncodingThreads.contains(id)) {
+
+ RecordingEncoding *thread = m_EncodingThreads[id];
+
+ //logDebug("Recording::event: thread = " + TQString::number((long long)thread, 16));
+
+ if (thread->error()) {
+ logError(thread->errorString());
+ //m_context.setError();
+ stopEncoder(id);
+ } else {
+ //TQ_UINT64 size = thread->encodedSize();
+ //m_context.setEncodedSize(low, high);
+ //notifyRecordingContextChanged(m_context);
+ if (e->type() == EncodingTerminated) {
+ stopEncoder(id);
+ } else if (e->type() == EncodingStep) {
+ SoundStreamEncodingStepEvent *step = static_cast<SoundStreamEncodingStepEvent*>(e);
+ size_t consumed_size = SIZE_T_DONT_CARE;
+ notifySoundStreamData(m_RawStreams2EncodedStreams[id], thread->config().m_SoundFormat,
+ step->data(), step->size(), consumed_size, step->metaData());
+ if (consumed_size != SIZE_T_DONT_CARE && consumed_size < step->size()) {
+ logError(i18n("Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes").arg(step->size() - consumed_size));
+ }
+ }
+ }
+ }
+ return true;
+ } else {
+ return TQObject::event(_e);
+ }
+}
+
+
+bool Recording::getSoundStreamDescription(SoundStreamID id, TQString &descr) const
+{
+ if (m_EncodedStreams2RawStreams.contains(id)) {
+ if (querySoundStreamDescription(m_EncodedStreams2RawStreams[id], descr)) {
+ descr = name() + " - " + descr;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Recording::getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const
+{
+ if (m_EncodedStreams2RawStreams.contains(id)) {
+ if (querySoundStreamRadioStation(m_EncodedStreams2RawStreams[id], rs)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool Recording::enumerateSoundStreams(TQMap<TQString, SoundStreamID> &list) const
+{
+ TQMapConstIterator<SoundStreamID,SoundStreamID> end = m_RawStreams2EncodedStreams.end();
+ for (TQMapConstIterator<SoundStreamID,SoundStreamID> it = m_RawStreams2EncodedStreams.begin(); it != end; ++it) {
+ TQString tmp = TQString();
+ getSoundStreamDescription(*it, tmp);
+ list[tmp] = *it;
+ }
+ return m_RawStreams2EncodedStreams.count() > 0;
+}
+
+
+bool Recording::noticeSoundStreamChanged(SoundStreamID id)
+{
+ if (m_RawStreams2EncodedStreams.contains(id)) {
+ notifySoundStreamChanged(m_RawStreams2EncodedStreams[id]);
+ return true;
+ }
+ return false;
+}
+
+
+bool Recording::isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (m_EncodingThreads.contains(id)) {
+ b = m_EncodingThreads[id]->running();
+ sf = getSoundFormat();
+ return true;
+ }
+ return false;
+}
+
+
+bool Recording::noticeSoundStreamClosed(SoundStreamID id)
+{
+ if (m_PreRecordingBuffers.contains(id)) {
+ if (m_PreRecordingBuffers[id])
+ delete m_PreRecordingBuffers[id];
+ m_PreRecordingBuffers.remove(id);
+ }
+
+ if (m_EncodingThreads.contains(id)) {
+ sendStopRecording(id);
+ return true;
+ }
+ return false;
+}
+
+
+#include "recording.moc"
diff --git a/plugins/recording/recording.h b/plugins/recording/recording.h
new file mode 100644
index 0000000..7d48331
--- /dev/null
+++ b/plugins/recording/recording.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ recording.h - description
+ -------------------
+ begin : Mi Aug 27 2003
+ copyright : (C) 2003 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_H
+#define KRADIO_RECORDING_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <tqobject.h>
+#include <tqstring.h>
+#include <tqmap.h>
+
+#include "../../src/include/plugins.h"
+#include "../../src/include/timecontrol_interfaces.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include "recording-config.h"
+#include "reccfg_interfaces.h"
+#include "encoder.h"
+
+class RadioStation;
+class StationList;
+class TQSocketNotifier;
+class RecordingEncoding;
+class FileRingBuffer;
+
+class Recording : public TQObject,
+ public PluginBase,
+ public ISoundStreamClient,
+ public IRecCfg
+{
+Q_OBJECT
+
+public:
+ Recording(const TQString &name);
+ ~Recording();
+
+ virtual TQString pluginClassName() const { return "Recording"; }
+
+ virtual const TQString &name() const { return PluginBase::name(); }
+ virtual TQString &name() { return PluginBase::name(); }
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+
+ bool isRecording () const;
+
+
+ // PluginBase
+
+public:
+ virtual void saveState (TDEConfig *) const;
+ virtual void restoreState (TDEConfig *);
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+protected:
+
+// IRecCfg
+
+ bool setEncoderBuffer (size_t BufferSize, size_t BufferCount);
+ bool setSoundFormat (const SoundFormat &sf);
+ bool setMP3Quality (int q);
+ bool setOggQuality (float q);
+ bool setRecordingDirectory(const TQString &dir);
+ bool setOutputFormat (RecordingConfig::OutputFormat of);
+ bool setPreRecording (bool enable, int seconds);
+ bool setRecordingConfig (const RecordingConfig &cfg);
+
+ void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const;
+ const SoundFormat &getSoundFormat () const;
+ int getMP3Quality () const;
+ float getOggQuality () const;
+ const TQString &getRecordingDirectory() const;
+ RecordingConfig::OutputFormat getOutputFormat() const;
+ bool getPreRecording(int &seconds) const;
+ const RecordingConfig &getRecordingConfig() const;
+
+// ISoundStreamClient
+
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+
+ bool startPlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+
+ bool startRecording(SoundStreamID id);
+ bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format);
+ bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md);
+ bool stopRecording(SoundStreamID id);
+ bool isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool getSoundStreamDescription(SoundStreamID id, TQString &descr) const;
+ bool getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamChanged(SoundStreamID id);
+
+ bool enumerateSoundStreams(TQMap<TQString, SoundStreamID> &list) const;
+
+protected slots:
+
+ bool event(TQEvent *e);
+
+protected:
+
+ bool startEncoder(SoundStreamID ssid, const RecordingConfig &cfg);
+ void stopEncoder(SoundStreamID ssid);
+
+protected:
+
+ RecordingConfig m_config;
+ TQMap<SoundStreamID, FileRingBuffer*> m_PreRecordingBuffers;
+
+ TQMap<SoundStreamID, RecordingEncoding*> m_EncodingThreads;
+ TQMap<SoundStreamID, SoundStreamID> m_RawStreams2EncodedStreams;
+ TQMap<SoundStreamID, SoundStreamID> m_EncodedStreams2RawStreams;
+};
+
+/* PreRecording Notes: listen for startplayback, stopplayback, closestream
+ manage map streamid => buffer
+ set each started stream into capture mode
+ put data into ringbuffers
+ on capture start, feed everything into the encoder buffer,
+ if encoderbuffer < prerecbuffer =>
+ put as much as possible into encoder
+ put new audio data into ring buffer
+
+*/
+
+#endif
diff --git a/plugins/recording/soundstreamevent.h b/plugins/recording/soundstreamevent.h
new file mode 100644
index 0000000..c7b986e
--- /dev/null
+++ b/plugins/recording/soundstreamevent.h
@@ -0,0 +1,87 @@
+/***************************************************************************
+ soundstreamevent.h - description
+ -------------------
+ begin : Fri May 06 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_RECORDING_SOUNDSTREAM_EVENT_H
+#define KRADIO_RECORDING_SOUNDSTREAM_EVENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <tqevent.h>
+
+#include "../../src/include/sound_metadata.h"
+
+const TQEvent::Type EncodingTerminated = (TQEvent::Type)(TQEvent::User+1);
+const TQEvent::Type EncodingStep = (TQEvent::Type)(TQEvent::User+2);
+
+class SoundStreamEvent : public TQEvent
+{
+public:
+ SoundStreamEvent(TQEvent::Type t, SoundStreamID id) : TQEvent(t), m_SSID(id) {}
+ const SoundStreamID &getSoundStreamID() const { return m_SSID; }
+
+ static bool isSoundStreamEvent (const TQEvent *e) { return e && ((e->type() == EncodingTerminated) || (e->type() == EncodingStep)); }
+
+protected:
+ SoundStreamID m_SSID;
+};
+
+
+
+
+
+
+class SoundStreamEncodingTerminatedEvent : public SoundStreamEvent
+{
+public:
+ SoundStreamEncodingTerminatedEvent(SoundStreamID id) : SoundStreamEvent(EncodingTerminated, id) {}
+};
+
+
+
+
+
+
+class SoundStreamEncodingStepEvent : public SoundStreamEvent
+{
+public:
+ SoundStreamEncodingStepEvent(SoundStreamID id, const char *data, size_t size, const SoundMetaData &md)
+ : SoundStreamEvent(EncodingStep, id),
+ m_Size(size),
+ m_MetaData(md)
+ {
+ m_Data = new char [m_Size];
+ memcpy (m_Data, data, m_Size);
+ }
+ virtual ~SoundStreamEncodingStepEvent() { freeData(); }
+
+ void freeData() { if (m_Data) delete m_Data; m_Data = NULL; m_Size = 0; } // _MUST_ be called by event receiver
+
+ const char *data() const { return m_Data; }
+ size_t size() const { return m_Size; }
+ const SoundMetaData &metaData() const { return m_MetaData; }
+
+ static bool isSoundStreamEncodingStep (const TQEvent *e) { return e && (e->type() == EncodingStep); }
+
+protected:
+ char *m_Data;
+ size_t m_Size;
+ SoundMetaData m_MetaData;
+};
+
+#endif