25 #include <QApplication> 29 #include <QStringList> 35 #include <KConfigGroup> 36 #include <KSharedConfig> 37 #include <kxmlgui_version.h> 64 #define OPEN_RETRY_TIME 1000 66 //*************************************************************************** 77 m_prerecording_queue(),
79 m_buffers_recorded(0),
115 qDebug(
"RecordPlugin::setup(%s)",
DBG(previous_params.join(
_(
","))));;
119 if (previous_params.count() == 1) {
120 const QString m = previous_params[0].toLower();
122 if (m ==
_(
"format"))
124 else if (m ==
_(
"source"))
126 else if (m ==
_(
"start_now"))
131 qDebug(
"RecordPlugin::setup(%s) - MODE=%d",
132 DBG(previous_params.join(
_(
","))), static_cast<int>(mode));
139 if (!m_dialog)
return Q_NULLPTR;
146 m_dialog = Q_NULLPTR;
153 connect(m_dialog, SIGNAL(sigDeviceChanged(QString)),
156 connect(m_dialog, SIGNAL(sigTracksChanged(uint)),
158 connect(m_dialog, SIGNAL(sampleRateChanged(
double)),
162 connect(m_dialog, SIGNAL(sigBitsPerSampleChanged(uint)),
168 connect(m_dialog, SIGNAL(sigBuffersChanged()),
173 connect(m_dialog, SIGNAL(sigTriggerChanged(
bool)),
176 m_dialog->params().record_trigger_enabled ||
177 m_dialog->params().start_time_enabled
180 connect(m_dialog, SIGNAL(sigPreRecordingChanged(
bool)),
182 connect(m_dialog, SIGNAL(sigPreRecordingChanged(
bool)),
205 Qt::QueuedConnection);
208 m_dialog->setSupportedTracks(0, 0);
217 QStringList *list =
new QStringList();
219 if (list && (m_dialog->exec() == QDialog::Accepted)) {
221 *list = m_dialog->params().toList();
224 if (list)
delete list;
241 m_dialog = Q_NULLPTR;
279 qDebug(
"RecordPlugin::setMethod(%d)", static_cast<int>(method));
285 bool searching =
false;
288 QString section =
_(
"plugin ") +
name();
289 KConfigGroup cfg = KSharedConfig::openConfig()->group(section);
292 QString device = cfg.readEntry(
293 _(
"last_device_%1").arg(static_cast<int>(method)));
299 #ifdef HAVE_OSS_SUPPORT 306 #ifdef HAVE_ALSA_SUPPORT 313 #ifdef HAVE_PULSEAUDIO_SUPPORT 320 #ifdef HAVE_QT_AUDIO_SUPPORT 327 qDebug(
"unsupported recording method (%d)",
328 static_cast<int>(method));
339 qDebug(
"unsupported recording method - trying next (%d)",
340 static_cast<int>(method));
350 qWarning(
"found no valid recording method");
360 QStringList supported_devices;
379 qDebug(
"RecordPlugin::retryOpen()");
391 qDebug(
"RecordPlugin::setDevice('%s')",
DBG(device));
396 QString dev = device;
398 if (!supported.isEmpty() && !supported.contains(device)) {
400 dev = supported.first();
401 qDebug(
"RecordPlugin::setDevice(%s) -> fallback to '%s'",
406 if (dev.startsWith(
_(
"#"))) {
408 qDebug(
"RecordPlugin::setDevice(%s) -> no valid device, using '%s'",
421 QString section =
_(
"plugin ") +
name();
422 KConfigGroup cfg = KSharedConfig::openConfig()->group(section);
423 cfg.writeEntry(
_(
"last_device_%1").arg(
428 if (!result.isNull()) {
429 bool shouldRetry =
false;
431 qWarning(
"RecordPlugin::setDevice('%s'): " 432 "opening the device failed. error message='%s'",
433 DBG(device),
DBG(result));
444 short_device_name +=
_(
", ") +
448 bool errIsNumeric =
false;
449 int errNumber = result.toInt(&errIsNumeric);
451 if (errNumber == ENODEV) {
453 "Maybe your system lacks support for the "\
454 "corresponding hardware or the hardware is not "\
457 }
else if (errNumber == EBUSY) {
459 "The audio device seems to be occupied by another "\
460 "application. Retrying..." 465 "Some unexpected error happened (%1). "\
466 "You may try an other recording method or "\
468 QString::fromLocal8Bit(strerror(errNumber))
473 if (result.length()) {
479 result, i18nc(
"%1 = a device name",
480 "Unable to open the recording device (%1)",
500 qDebug(
"RecordPlugin::setDevice('%s') failed, " 501 "returning to 'UNINITIALIZED'",
DBG(device));
525 unsigned int min = 0;
526 unsigned int max = 0;
529 if (min > max) min = max;
531 unsigned int channels = new_tracks;
532 if ((channels < min) || (channels > max)) {
534 if (channels < min) channels = min;
535 if (channels > max) channels = max;
536 qDebug(
"RecordPlugin::changeTracks(%u) -> clipped to %u",
537 new_tracks, channels);
539 if ((new_tracks && channels) && (new_tracks != channels)) {
541 switch (new_tracks) {
542 case 1: s1 = i18n(
"Mono");
break;
543 case 2: s1 = i18n(
"Stereo");
break;
544 case 4: s1 = i18n(
"Quadro");
break;
546 s1 = i18n(
"%1 channels", new_tracks);
550 case 1: s2 = i18n(
"Mono");
break;
551 case 2: s2 = i18n(
"Stereo");
break;
552 case 4: s2 = i18n(
"Quadro");
break;
554 s2 = i18n(
"%1 channels", channels);
557 notice(i18n(
"%1 is not supported, using %2", s1, s2));
560 Q_ASSERT(channels >= min);
561 Q_ASSERT(channels <= max);
572 if (channels < min) channels = min;
573 if (channels > max) channels = max;
579 if (new_tracks && (channels > 0))
notice(
580 i18n(
"Recording with %1 channel(s) failed, "\
581 "using %2 channel(s)", new_tracks, channels));
607 bool is_supported =
false;
608 foreach (
const double &r, supported_rates)
609 if (qFuzzyCompare(new_rate, r)) { is_supported =
true;
break; }
610 double rate = new_rate;
611 if (!is_supported && !supported_rates.isEmpty()) {
613 double nearest = supported_rates.last();
614 foreach (
double r, supported_rates) {
615 if (fabs(r - rate) <= fabs(nearest - rate))
625 notice(i18n(
"%1 Hz is not supported, "\
626 "using %2 Hz", sr1, sr2));
635 if (rate < 0) rate = 0;
642 notice(i18n(
"%1 Hz failed, using %2 Hz", sr1, sr2));
669 QList<Kwave::Compression::Type> supported_comps =
672 if (!supported_comps.contains(compression) &&
677 if (!supported_comps.isEmpty() &&
678 !supported_comps.contains(compression))
682 compression = supported_comps[0];
685 if (compression != new_compression) {
688 notice(i18n(
"Compression '%1' not supported, using '%2'", c1, c2));
700 notice(i18n(
"Compression '%1' failed, using '%2'.", c1 ,c2));
729 if (!supported_bits.contains(bits) && !supported_bits.isEmpty()) {
731 int nearest = supported_bits.last();
732 foreach (
unsigned int b, supported_bits) {
733 if (qAbs(
Kwave::toInt(b) - nearest) <= qAbs(bits - nearest))
739 i18n(
"%1 bits per sample is not supported, "\
740 "using %2 bits per sample",
750 if (bits < 0) bits = 0;
751 if ((new_bits > 0) && (bits > 0))
notice(
752 i18n(
"%1 bits per sample failed, " 753 "using %2 bits per sample",
778 QList<Kwave::SampleFormat::Format> supported_formats =
781 if (!supported_formats.contains(format) && !supported_formats.isEmpty()) {
786 if (!supported_formats.contains(format)) {
787 format = supported_formats.first();
793 if (!(new_format == -1) && !(new_format == format)) {
794 notice(i18n(
"Sample format '%1' is not supported, "\
795 "using '%2'", s1, s2));
810 i18n(
"Sample format '%1' failed, using '%2'", s1, s2));
828 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
884 if (params.
tracks < 1)
return false;
899 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
901 if (!accepted)
return;
949 i18n(
"The current sample format is not supported!")
955 i18n(
"The current compression type is not supported!")
990 unsigned int buf_size = params.
tracks *
1011 if (!tracks)
return;
1023 rate).arg(bits).arg(tracks));
1024 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1031 if (!qFuzzyCompare(mgr.
rate(), rate) || (mgr.
bits() != bits) ||
1032 (mgr.
tracks() != tracks))
1065 const KAboutData about_data = KAboutData::applicationData();
1066 QString software = about_data.componentName() +
_(
"-") +
1067 about_data.version() +
_(
" ") +
1068 i18n(
"(built with KDE Frameworks %1)",
1069 _(KXMLGUI_VERSION_STRING));
1073 QDate now(QDate::currentDate());
1075 date = date.sprintf(
"%04d-%02d-%02d",
1076 now.year(), now.month(), now.day());
1088 qDebug(
"RecordPlugin::recordStopped(%d)", reason);
1089 if (reason >= 0)
return;
1095 err_msg = i18n(
"Buffer overrun. Please increase the "\
1096 "number and/or size of the record buffers.");
1099 err_msg = i18n(
"The recording device seems to be busy.");
1102 err_msg = i18n(
"Reading from the recording device failed. "\
1103 "Error number = %1 (%2)", -reason,
1104 QString::fromLocal8Bit(strerror(-reason)));
1109 qDebug(
"RecordPlugin::recordStopped(): last=%lu",
1110 static_cast<unsigned long int>(
1172 if (remaining > buffers_total) remaining = buffers_total;
1178 if (!queued) buffers_total = 0;
1185 unsigned int bytes_per_sample,
1187 unsigned int tracks)
1189 unsigned int samples = raw_data.size() / bytes_per_sample / tracks;
1194 static int saw[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1195 raw_data.fill(0x05);
1196 for (
unsigned int s = 0; s < samples; s++) {
1198 for (
unsigned int byte = 0; byte < bytes_per_sample; byte++) {
1199 quint8 x = (quint8)v;
1200 raw_data[(((s * tracks) + track) * bytes_per_sample) + byte] = x;
1204 const int max = (1 << ((bytes_per_sample * 8) - 1)) - 1;
1205 saw[track] += max / 64;
1206 if (saw[track] >= max) saw[track] = 0;
1214 switch (bytes_per_sample) {
1218 reinterpret_cast<const quint8 *
>(raw_data.constData());
1220 reinterpret_cast<quint8 *
>(dest.data());
1232 const quint16 *src =
1233 reinterpret_cast<const quint16 *
>(raw_data.constData());
1235 reinterpret_cast<quint16 *
>(dest.data());
1248 reinterpret_cast<const quint8 *
>(raw_data.constData());
1250 reinterpret_cast<quint8 *
>(dest.data());
1253 *(dst++) = *(src++);
1254 *(dst++) = *(src++);
1255 *(dst++) = *(src++);
1256 src += (tracks - 1) * 3;
1263 const quint32 *src =
1264 reinterpret_cast<const quint32 *
>(raw_data.constData());
1266 reinterpret_cast<quint32 *
>(dest.data());
1278 const quint64 *src =
1279 reinterpret_cast<const quint64 *
>(raw_data.constData());
1281 reinterpret_cast<quint64 *
>(dest.data());
1294 reinterpret_cast<const quint8 *
>(raw_data.constData());
1296 reinterpret_cast<quint8 *
>(dest.data());
1297 src += (track * bytes_per_sample);
1298 unsigned int increment = (tracks - 1) * bytes_per_sample;
1300 for (
unsigned int b = 0; b < bytes_per_sample; b++) {
1330 if (!buffer.
size())
return false;
1337 float trigger =
static_cast<float>(
1339 const float rate =
static_cast<const float>(
1362 const float f_rise = 20.0f;
1363 float Fg = f_rise / rate;
1364 float n = 1.0f / tanf(
float(M_PI) * Fg);
1365 const float a0_r = 1.0f / (1.0f + n);
1366 const float b1_r = (1.0f - n) / (1.0f + n);
1369 const float f_fall = 1.0f;
1371 n = 1.0f / tanf(
float(M_PI) * Fg);
1372 const float a0_f = 1.0f / (1.0f + n);
1373 const float b1_f = (1.0f - n) / (1.0f + n);
1377 for (
unsigned int t = 0; t < buffer.
size(); ++t) {
1382 y = (a0_r * x) + (a0_r * last_x) - (b1_r * y);
1386 y = (a0_f * x) + (a0_f * last_x) - (b1_f * y);
1393 if (y > trigger)
return true;
1397 qDebug(
">> level=%5.3g, trigger=%5.3g", y, trigger);
1425 const unsigned int tracks = params.
tracks;
1427 if (!tracks)
return;
1433 for (
unsigned int track=0; track < tracks; ++track) {
1436 if (!fifo.
length())
continue;
1444 unsigned int rest = fifo.
length();
1446 unsigned int read = fifo.
get(buffer);
1447 if (read < 1)
break;
1448 writer->
write(buffer, read);
1455 Q_ASSERT(fifo.
length() == 0);
1468 bool recording_done =
false;
1482 const unsigned int tracks = params.
tracks;
1484 if (!tracks)
return;
1487 Q_ASSERT(bytes_per_sample);
1488 if (!bytes_per_sample)
return;
1490 unsigned int samples = (buffer.size() / bytes_per_sample) / tracks;
1492 if (!samples)
return;
1500 if (already_recorded + samples >= limit) {
1504 (limit > already_recorded) ?
1505 (limit - already_recorded) : 0);
1506 buffer.resize(samples * tracks * bytes_per_sample);
1508 recording_done =
true;
1513 buf.resize(bytes_per_sample * samples);
1514 Q_ASSERT(buf.size() ==
Kwave::toInt(bytes_per_sample * samples));
1515 if (buf.size() !=
Kwave::toInt(bytes_per_sample * samples))
return;
1518 Q_ASSERT(decoded.
size() == samples);
1519 if (decoded.
size() != samples)
return;
1528 for (
unsigned int track=0; track < tracks; ++track) {
1530 split(buffer, buf, bytes_per_sample, track, tracks);
1546 for (
unsigned int track=0; track < tracks; ++track) {
1549 split(buffer, buf, bytes_per_sample, track, tracks);
1586 if (writer) (*writer) << decoded;
1598 if (recording_done &&
1615 #include "RecordPlugin.moc" void notice(QString message)
void split(QByteArray &raw_data, QByteArray &dest, unsigned int bytes_per_sample, unsigned int track, unsigned int tracks)
virtual QString open(const QString &dev)=0
void enablePrerecording(bool enable)
void sigRecordedSamples(sample_index_t samples_recorded)
void emitCommand(const QString &command)
void setBitsPerSample(unsigned int bits)
virtual unsigned int tracks() const Q_DECL_OVERRIDE
unsigned int bits_per_sample
Kwave::SampleDecoder * m_decoder
void changeBitsPerSample(unsigned int new_bits)
Kwave::RecordThread * m_thread
void updateBufferState(unsigned int count, unsigned int total)
void setTracks(unsigned int tracks)
void deviceRecordStarted()
virtual bool write(const Kwave::SampleArray &buffer, unsigned int &count)=0
void prerecordingChanged(bool enable)
void recordStopped(int reason)
void enqueuePrerecording(unsigned int track, const Kwave::SampleArray &decoded)
virtual unsigned int rawBytesPerSample()=0
QString rate2string(double rate) const
QString description(IDX type, bool localized) const
virtual QString fileFilter()
virtual QList< unsigned int > supportedBits()=0
virtual int setSampleRate(double &new_rate)=0
QWidget * parentWidget() const
virtual int bitsPerSample()=0
bool checkTrigger(unsigned int track, const Kwave::SampleArray &buffer)
void setSupportedBits(const QList< unsigned int > &bits)
Kwave::RecordState m_state
Kwave::SignalManager & signalManager()
void changeTracks(unsigned int new_tracks)
static int sorry(QWidget *widget, QString message, QString caption=QString())
virtual QString name() const
virtual int setTracks(unsigned int &tracks)=0
RecordPlugin(QObject *parent, const QVariantList &args)
Kwave::record_method_t m_method
virtual void migrateToActiveContext()
unsigned int m_buffers_recorded
int setBuffers(unsigned int count, unsigned int size)
virtual int setCompression(Kwave::Compression::Type new_compression)=0
unsigned int pre_record_time
Kwave::MultiTrackWriter * m_writers
void flushPrerecordingQueue()
virtual int detectTracks(unsigned int &min, unsigned int &max)=0
void resetRecording(bool &accepted)
Kwave::PluginManager & manager() const
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
QVector< float > m_trigger_value
Kwave::SignalManager & signalManager()
void set(FileProperty key, const QVariant &value)
virtual QStringList * setup(QStringList &previous_params) Q_DECL_OVERRIDE
virtual sample_index_t last() const
void setRate(double rate)
void setFileInfo(const Kwave::FileInfo &new_info, bool with_undo)
void setEmpty(bool empty)
void setCompression(int compression)
unsigned int record_trigger
virtual QList< Kwave::Compression::Type > detectCompressions()=0
void changeCompression(Kwave::Compression::Type new_compression)
virtual QStringList supportedDevices()=0
void setMethod(Kwave::record_method_t method)
static int error(QWidget *widget, QString message, QString caption=QString())
void setMethod(Kwave::record_method_t method)
virtual QList< double > detectSampleRates()=0
unsigned int m_inhibit_count
virtual int setBitsPerSample(unsigned int new_bits)=0
Kwave::RecordDialog * m_dialog
virtual ~RecordPlugin() Q_DECL_OVERRIDE
void setLength(sample_index_t length)
void setTracks(unsigned int tracks)
virtual QList< Kwave::SampleFormat::Format > detectSampleFormats()=0
virtual unsigned int get(Kwave::SampleArray &buffer)
Kwave::RecordDevice * m_device
void stateChanged(Kwave::RecordState state)
virtual double sampleRate()=0
void setSupportedSampleRates(const QList< double > &rates)
void changeSampleRate(double new_rate)
virtual sample_index_t signalLength()
virtual Kwave::Compression::Type compression()=0
void enableTrigger(bool enable)
static float sample2float(const sample_t s)
void setSampleRate(double new_rate)
virtual void decode(QByteArray &raw_data, Kwave::SampleArray &decoded)=0
void deviceTriggerReached()
void setSupportedTracks(unsigned int min, unsigned int max)
bool record_trigger_enabled
void setSampleFormat(Kwave::SampleFormat::Format sample_format)
void setBits(unsigned int bits)
virtual unsigned int length()
static double saw(double param)
Kwave::RecordController m_controller
unsigned int queuedBuffers()
virtual unsigned int blockSize() const
virtual Kwave::SampleFormat::Format sampleFormat()=0
Kwave::RecordParams & params()
QVector< Kwave::SampleFIFO > m_prerecording_queue
void changeSampleFormat(Kwave::SampleFormat::Format new_format)
Kwave::SampleFormat::Format sample_format
#define KWAVE_PLUGIN(name, class)
unsigned int bits() const
void setDevice(const QString &device)
void setDevice(const QString &device)
unsigned int size() const
void setSupportedDevices(QStringList devices)
void updateBufferProgressBar()
virtual int stop(unsigned int timeout=10000)
void setInitialized(bool initialized)
virtual void clear() Q_DECL_OVERRIDE
virtual int setSampleFormat(Kwave::SampleFormat::Format new_format)=0
void updateEffects(unsigned int track, Kwave::SampleArray &buffer)
Kwave::Compression::Type compression
unsigned int buffer_count
virtual Kwave::byte_order_t endianness()=0
void setFileFilter(const QString &filter)
void setSupportedSampleFormats(const QList< Kwave::SampleFormat::Format > &formats)
IDX findFromData(const DATA &data) const
void setRecordDevice(Kwave::RecordDevice *device)
unsigned int remainingBuffers()
void setSupportedCompressions(const QList< Kwave::Compression::Type > &comps)
QStringList defaultParams(const QString &name)
void message(const QString &message)