From 7696ef13c13aea0da9acada8abb149967aaf8a90 Mon Sep 17 00:00:00 2001 From: trialuser02 Date: Tue, 3 Jan 2017 18:39:36 +0000 Subject: 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 --- src/plugins/Output/shout/settingsdialog.cpp | 64 +++++++++ src/plugins/Output/shout/settingsdialog.h | 45 +++++++ src/plugins/Output/shout/settingsdialog.ui | 196 ++++++++++++++++++++++++++++ src/plugins/Output/shout/shoutclient.cpp | 24 ++-- src/plugins/Output/shout/shoutoutput.cpp | 60 +++++++-- src/plugins/Output/shout/shoutoutput.h | 5 + 6 files changed, 376 insertions(+), 18 deletions(-) create mode 100644 src/plugins/Output/shout/settingsdialog.cpp create mode 100644 src/plugins/Output/shout/settingsdialog.h create mode 100644 src/plugins/Output/shout/settingsdialog.ui (limited to 'src/plugins/Output') 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 +#include +#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 + +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 @@ + + + SettingsDialog + + + + 0 + 0 + 450 + 302 + + + + Connection Settings + + + + QFormLayout::AllNonFixedFieldsGrow + + + 6 + + + 6 + + + 6 + + + + + Host: + + + + + + + + + + Port: + + + + + + + 65535 + + + + + + + Mount point: + + + + + + + + + + User: + + + + + + + + + + Password: + + + + + + + + + + Quality: + + + + + + + 0.200000000000000 + + + 1.000000000000000 + + + 0.010000000000000 + + + + + + + Sample rate: + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Public + + + + + + + Hz + + + 8000 + + + 96000 + + + 100 + + + 44100 + + + + + + + + + buttonBox + accepted() + SettingsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SettingsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + 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 +#include +#include #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 -#include +#include +#include #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(data + (i * chan) * sizeof(float)); - buffer[1][i] = *reinterpret_cast(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 +#include #include #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 -- cgit v1.2.3-13-gbd6f