aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Output/shout
diff options
context:
space:
mode:
authortrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2017-01-03 18:39:36 +0000
committertrialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38>2017-01-03 18:39:36 +0000
commit7696ef13c13aea0da9acada8abb149967aaf8a90 (patch)
treecd700a27da47071bc605fe2cc88992d940de2307 /src/plugins/Output/shout
parent28dda78e5036bae2bd317decf950ba9f6caea780 (diff)
downloadqmmp-7696ef13c13aea0da9acada8abb149967aaf8a90.tar.gz
qmmp-7696ef13c13aea0da9acada8abb149967aaf8a90.tar.bz2
qmmp-7696ef13c13aea0da9acada8abb149967aaf8a90.zip
icecast plugin: added resampler and settings dialog
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@6930 90c681e8-e032-0410-971d-27865f9a5e38
Diffstat (limited to 'src/plugins/Output/shout')
-rw-r--r--src/plugins/Output/shout/settingsdialog.cpp64
-rw-r--r--src/plugins/Output/shout/settingsdialog.h45
-rw-r--r--src/plugins/Output/shout/settingsdialog.ui196
-rw-r--r--src/plugins/Output/shout/shoutclient.cpp24
-rw-r--r--src/plugins/Output/shout/shoutoutput.cpp60
-rw-r--r--src/plugins/Output/shout/shoutoutput.h5
6 files changed, 376 insertions, 18 deletions
diff --git a/src/plugins/Output/shout/settingsdialog.cpp b/src/plugins/Output/shout/settingsdialog.cpp
new file mode 100644
index 000000000..0e72144ea
--- /dev/null
+++ b/src/plugins/Output/shout/settingsdialog.cpp
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#include <QSettings>
+#include <qmmp/qmmp.h>
+#include "settingsdialog.h"
+#include "ui_settingsdialog.h"
+
+SettingsDialog::SettingsDialog(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::SettingsDialog)
+{
+ m_ui->setupUi(this);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Shout");
+ m_ui->hostLineEdit->setText(settings.value("host", "127.0.0.1").toString());
+ m_ui->portSpinBox->setValue(settings.value("port", 8000).toInt());
+ m_ui->mountPointLineEdit->setText(settings.value("mount", "qmmp.out").toString());
+ m_ui->userLineEdit->setText(settings.value("user", "source").toString());
+ m_ui->passwLineEdit->setText(settings.value("passw", "hackme").toString());
+ m_ui->publicCheckBox->setChecked(settings.value("public", false).toBool());
+ m_ui->qualitySpinBox->setValue(settings.value("vorbis_quality", 0.8).toDouble());
+ m_ui->srateSpinBox->setValue(settings.value("sample_rate", 44100).toInt());
+ settings.endGroup();
+}
+
+SettingsDialog::~SettingsDialog()
+{
+ delete m_ui;
+}
+
+void SettingsDialog::accept()
+{
+ QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Shout");
+ settings.setValue("host", m_ui->hostLineEdit->text());
+ settings.setValue("port", m_ui->portSpinBox->value());
+ settings.setValue("mount", m_ui->mountPointLineEdit->text());
+ settings.setValue("user", m_ui->userLineEdit->text());
+ settings.setValue("passw", m_ui->passwLineEdit->text());
+ settings.setValue("public", m_ui->publicCheckBox->isChecked());
+ settings.setValue("vorbis_quality", m_ui->qualitySpinBox->value());
+ settings.setValue("sample_rate", m_ui->srateSpinBox->value());
+ settings.endGroup();
+ QDialog::accept();
+}
diff --git a/src/plugins/Output/shout/settingsdialog.h b/src/plugins/Output/shout/settingsdialog.h
new file mode 100644
index 000000000..0b05b5520
--- /dev/null
+++ b/src/plugins/Output/shout/settingsdialog.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2017 by Ilya Kotov *
+ * forkotov02@hotmail.ru *
+ * *
+ * 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. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef SETTINGSDIALOG_H
+#define SETTINGSDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class SettingsDialog;
+}
+
+class SettingsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit SettingsDialog(QWidget *parent = 0);
+ ~SettingsDialog();
+
+public slots:
+ void accept();
+
+private:
+ Ui::SettingsDialog *m_ui;
+};
+
+#endif // SETTINGSDIALOG_H
diff --git a/src/plugins/Output/shout/settingsdialog.ui b/src/plugins/Output/shout/settingsdialog.ui
new file mode 100644
index 000000000..e1e20048f
--- /dev/null
+++ b/src/plugins/Output/shout/settingsdialog.ui
@@ -0,0 +1,196 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDialog</class>
+ <widget class="QDialog" name="SettingsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>450</width>
+ <height>302</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Connection Settings</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
+ </property>
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Host:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="hostLineEdit"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="portSpinBox">
+ <property name="maximum">
+ <number>65535</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Mount point:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="mountPointLineEdit"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>User:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="userLineEdit"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QLineEdit" name="passwLineEdit"/>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Quality:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QDoubleSpinBox" name="qualitySpinBox">
+ <property name="minimum">
+ <double>0.200000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>1.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.010000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Sample rate:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <widget class="QCheckBox" name="publicCheckBox">
+ <property name="text">
+ <string>Public</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QSpinBox" name="srateSpinBox">
+ <property name="suffix">
+ <string>Hz</string>
+ </property>
+ <property name="minimum">
+ <number>8000</number>
+ </property>
+ <property name="maximum">
+ <number>96000</number>
+ </property>
+ <property name="singleStep">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>44100</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>SettingsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/Output/shout/shoutclient.cpp b/src/plugins/Output/shout/shoutclient.cpp
index 45c5d5614..cf4efbf92 100644
--- a/src/plugins/Output/shout/shoutclient.cpp
+++ b/src/plugins/Output/shout/shoutclient.cpp
@@ -19,6 +19,8 @@
***************************************************************************/
#include <QTimer>
+#include <QSettings>
+#include <qmmp/qmmp.h>
#include "shoutclient.h"
ShoutClient::ShoutClient(QObject *parent) :
@@ -42,19 +44,25 @@ ShoutClient::~ShoutClient()
void ShoutClient::readSettings()
{
- shout_set_host(m_shout_conn, "127.0.0.1");
- shout_set_port(m_shout_conn, 8000);
- shout_set_password(m_shout_conn, "hackme");
- shout_set_mount(m_shout_conn, "/qmmp.out");
+ QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Shout");
+ shout_set_host(m_shout_conn, settings.value("host", "127.0.0.1").toString().toLatin1().constData());
+ shout_set_port(m_shout_conn, settings.value("port", 8000).toInt());
+ shout_set_password(m_shout_conn, settings.value("passw", "hackme").toString().toLatin1().constData());
+ shout_set_mount(m_shout_conn, QString("/%1").arg(settings.value("mount", "qmmp.out").toString()).
+ toLatin1().constData());
shout_set_name(m_shout_conn, "qmmp");
- shout_set_user(m_shout_conn, "source");
- shout_set_public(m_shout_conn, 0);
+ shout_set_user(m_shout_conn, settings.value("user", "source").toString().toLatin1().constData());
+ shout_set_public(m_shout_conn, settings.value("public", false).toBool() ? 1 : 0);
shout_set_format(m_shout_conn, SHOUT_FORMAT_OGG);
shout_set_protocol(m_shout_conn, SHOUT_PROTOCOL_HTTP);
shout_set_agent(m_shout_conn, "qmmp");
shout_set_audio_info(m_shout_conn, SHOUT_AI_CHANNELS, "2");
- shout_set_audio_info(m_shout_conn, SHOUT_AI_QUALITY, "0.4");
- shout_set_audio_info(m_shout_conn, SHOUT_AI_SAMPLERATE, "44100");
+ shout_set_audio_info(m_shout_conn, SHOUT_AI_QUALITY,
+ QString::number(settings.value("vorbis_quality", 0.8).toDouble(), 'f').toLatin1().constData());
+ shout_set_audio_info(m_shout_conn, SHOUT_AI_SAMPLERATE,
+ QString::number(settings.value("sample_rate", 44100).toInt()).toLatin1().constData());
+ settings.endGroup();
}
bool ShoutClient::open()
diff --git a/src/plugins/Output/shout/shoutoutput.cpp b/src/plugins/Output/shout/shoutoutput.cpp
index bb0fd2bfc..d27bd81c7 100644
--- a/src/plugins/Output/shout/shoutoutput.cpp
+++ b/src/plugins/Output/shout/shoutoutput.cpp
@@ -19,13 +19,18 @@
***************************************************************************/
#include <QFile>
-#include <unistd.h>
+#include <QSettings>
+#include <qmmp/qmmp.h>
#include "shoutoutput.h"
ShoutOutput::ShoutOutput(ShoutClient *m)
{
m_client = m;
-
+ m_soxr = 0;
+ m_ratio = 0;
+ m_soxr_buf = 0;
+ m_soxr_buf_frames = 0;
+ qsrand(time(NULL));
}
ShoutOutput::~ShoutOutput()
@@ -36,20 +41,33 @@ ShoutOutput::~ShoutOutput()
vorbis_dsp_clear(&m_vd);
vorbis_comment_clear(&m_vc);
vorbis_info_clear(&m_vi);
+ if(m_soxr)
+ {
+ soxr_delete(m_soxr);
+ m_soxr = 0;
+ }
}
bool ShoutOutput::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat)
{
+ QSettings settings(Qmmp::configFile(), QSettings::IniFormat);
+ float quality = settings.value("Shout/vorbis_quality", 0.8).toFloat();
+ quint32 outFreq = settings.value("Shout/sample_rate", 44100).toInt();
+
+ if(freq != outFreq)
+ {
+ m_soxr = soxr_create(freq, outFreq, map.size(), 0, 0, 0, 0);
+ m_ratio = (double)outFreq/freq;
+ }
+
vorbis_info_init(&m_vi);
- vorbis_encode_init_vbr(&m_vi,2,freq,.4);
+ vorbis_encode_init_vbr(&m_vi,2,outFreq, quality);
vorbis_comment_init(&m_vc);
- //vorbis_comment_add_tag(&m_vc,"TITLE","encoder_example.c");
vorbis_analysis_init(&m_vd, &m_vi);
vorbis_block_init(&m_vd,&m_vb);
- qsrand(time(NULL));
ogg_stream_init(&m_os,qrand());
configure(freq, map, Qmmp::PCM_FLOAT);
@@ -65,19 +83,42 @@ qint64 ShoutOutput::writeAudio(unsigned char *data, qint64 maxSize)
{
int chan = channels();
int frames = maxSize / chan / sizeof(float);
+ float *input_data = 0;
+
+ if(m_soxr)
+ {
+ size_t required_frames = double(frames) * m_ratio * 2 + 2;
+ if(required_frames > m_soxr_buf_frames)
+ {
+ m_soxr_buf_frames = required_frames;
+ m_soxr_buf = (float *)realloc(m_soxr_buf, m_soxr_buf_frames * sizeof(float) * chan);
+ }
+
+ size_t done = 0;
+ soxr_process(m_soxr, data, frames, 0, m_soxr_buf, m_soxr_buf_frames, &done);
+ input_data = m_soxr_buf;
+ if(done == 0) //soxr requires more data
+ return maxSize;
+ frames = done;
+ }
+ else
+ {
+ input_data = (float *)data;
+ }
+
float **buffer = vorbis_analysis_buffer(&m_vd, frames);
if(chan == 1)
{
- memcpy(buffer[0], data, frames * sizeof(float));
- memcpy(buffer[1], data, frames * sizeof(float));
+ memcpy(buffer[0], input_data, frames * sizeof(float));
+ memcpy(buffer[1], input_data, frames * sizeof(float));
}
else
{
for(int i = 0; i < frames; i++)
{
- buffer[0][i] = *reinterpret_cast<float *>(data + (i * chan) * sizeof(float));
- buffer[1][i] = *reinterpret_cast<float *>(data + (i * chan + 1) * sizeof(float));
+ buffer[0][i] = input_data[i * chan];
+ buffer[1][i] = input_data[i * chan + 1];
}
}
@@ -131,7 +172,6 @@ qint64 ShoutOutput::writeAudio(unsigned char *data, qint64 maxSize)
if(!m_client->open())
return -1;
- qsrand(time(NULL));
ogg_stream_reset(&m_os);
ogg_stream_init(&m_os,qrand());
diff --git a/src/plugins/Output/shout/shoutoutput.h b/src/plugins/Output/shout/shoutoutput.h
index 69f06a443..4d09a1a4a 100644
--- a/src/plugins/Output/shout/shoutoutput.h
+++ b/src/plugins/Output/shout/shoutoutput.h
@@ -22,6 +22,7 @@
#define SHOUTOUTPUT_H
#include <vorbis/vorbisenc.h>
+#include <soxr.h>
#include <qmmp/output.h>
#include "shoutclient.h"
@@ -48,6 +49,10 @@ private:
vorbis_comment m_vc; //struct that stores all the user comments
vorbis_dsp_state m_vd; //central working state for the packet->PCM decoder
vorbis_block m_vb; //local working space for packet->PCM decode
+ soxr_t m_soxr;
+ float *m_soxr_buf;
+ size_t m_soxr_buf_frames;
+ double m_ratio;
};
#endif // SHOUTOUTPUT_H