kwave  18.07.70
Kwave::RecordPlugin Class Reference

#include <RecordPlugin.h>

Inheritance diagram for Kwave::RecordPlugin:
Inheritance graph
Collaboration diagram for Kwave::RecordPlugin:
Collaboration graph

Classes

class  InhibitRecordGuard
 

Signals

void sigRecordedSamples (sample_index_t samples_recorded)
 
- Signals inherited from Kwave::Plugin
void sigRunning (Kwave::Plugin *plugin)
 
void sigDone (Kwave::Plugin *plugin)
 
void sigClosed (Kwave::Plugin *p)
 
void sigCommand (const QString &command)
 
void setProgressText (const QString &text)
 

Public Member Functions

 RecordPlugin (QObject *parent, const QVariantList &args)
 
virtual ~RecordPlugin () Q_DECL_OVERRIDE
 
virtual QStringList * setup (QStringList &previous_params) Q_DECL_OVERRIDE
 
- Public Member Functions inherited from Kwave::Plugin
 Plugin (QObject *parent, const QVariantList &args)
 
virtual ~Plugin () Q_DECL_OVERRIDE
 
virtual QString name () const
 
virtual QString description () const
 
virtual QString progressText ()
 
virtual bool canClose () const
 
bool isRunning () const
 
bool shouldStop () const
 
virtual void load (QStringList &params)
 
virtual void unload ()
 
virtual int start (QStringList &params)
 
virtual int stop ()
 
virtual void run (QStringList params)
 
Kwave::PluginManagermanager () const
 
Kwave::SignalManagersignalManager ()
 
QWidget * parentWidget () const
 
QString signalName ()
 
virtual sample_index_t signalLength ()
 
virtual double signalRate ()
 
virtual const QList< unsigned int > selectedTracks ()
 
virtual sample_index_t selection (QList< unsigned int > *tracks=Q_NULLPTR, sample_index_t *left=Q_NULLPTR, sample_index_t *right=Q_NULLPTR, bool expand_if_empty=false)
 
virtual void selectRange (sample_index_t offset, sample_index_t length)
 
virtual void migrateToActiveContext ()
 
- Public Member Functions inherited from Kwave::Runnable
virtual ~Runnable ()
 

Protected Slots

void resetRecording (bool &accepted)
 
void startRecording ()
 
void recordStopped (int reason)
 
void stateChanged (Kwave::RecordState state)
 

Protected Member Functions

void enterInhibit ()
 
void leaveInhibit ()
 
- Protected Member Functions inherited from Kwave::Plugin
int execute (QStringList &params)
 
void emitCommand (const QString &command)
 
void use ()
 
void setPluginManager (Kwave::PluginManager *new_plugin_manager)
 
virtual void run_wrapper (const QVariant &params) Q_DECL_OVERRIDE
 

Private Slots

void setMethod (Kwave::record_method_t method)
 
void setDevice (const QString &device)
 
void changeTracks (unsigned int new_tracks)
 
void changeSampleRate (double new_rate)
 
void changeCompression (Kwave::Compression::Type new_compression)
 
void changeBitsPerSample (unsigned int new_bits)
 
void changeSampleFormat (Kwave::SampleFormat::Format new_format)
 
void processBuffer ()
 
void buffersChanged ()
 
void prerecordingChanged (bool enable)
 
void retryOpen ()
 

Private Member Functions

void closeDevice ()
 
void notice (QString message)
 
void setupRecordThread ()
 
void updateBufferProgressBar ()
 
bool checkTrigger (unsigned int track, const Kwave::SampleArray &buffer)
 
void split (QByteArray &raw_data, QByteArray &dest, unsigned int bytes_per_sample, unsigned int track, unsigned int tracks)
 
void enqueuePrerecording (unsigned int track, const Kwave::SampleArray &decoded)
 
void flushPrerecordingQueue ()
 
bool paramsValid ()
 

Private Attributes

Kwave::record_method_t m_method
 
QString m_device_name
 
Kwave::RecordController m_controller
 
Kwave::RecordState m_state
 
Kwave::RecordDevicem_device
 
Kwave::RecordDialogm_dialog
 
Kwave::RecordThreadm_thread
 
Kwave::SampleDecoderm_decoder
 
QVector< Kwave::SampleFIFOm_prerecording_queue
 
Kwave::MultiTrackWriterm_writers
 
unsigned int m_buffers_recorded
 
unsigned int m_inhibit_count
 
QVector< float > m_trigger_value
 
QTimer m_retry_timer
 

Friends

class InhibitRecordGuard
 

Additional Inherited Members

- Public Slots inherited from Kwave::Plugin
virtual void setProgressDialogEnabled (bool enable)
 
virtual void updateProgress (qreal progress)
 
virtual void cancel ()
 
virtual void close ()
 
void release ()
 

Detailed Description

Definition at line 51 of file RecordPlugin.h.

Constructor & Destructor Documentation

◆ RecordPlugin()

Kwave::RecordPlugin::RecordPlugin ( QObject *  parent,
const QVariantList &  args 
)

Constructor

Parameters
parentreference to our plugin manager
argsargument list [unused]

Definition at line 67 of file RecordPlugin.cpp.

References Kwave::connect(), m_retry_timer, and retryOpen().

68  :Kwave::Plugin(parent, args),
70  m_device_name(),
71  m_controller(),
73  m_device(Q_NULLPTR),
74  m_dialog(Q_NULLPTR),
75  m_thread(Q_NULLPTR),
76  m_decoder(Q_NULLPTR),
78  m_writers(Q_NULLPTR),
80  m_inhibit_count(0),
83 {
84  m_retry_timer.setSingleShot(true);
85  connect(&m_retry_timer, SIGNAL(timeout()),
86  this, SLOT(retryOpen()),
87  Qt::QueuedConnection
88  );
89 }
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
Kwave::RecordState m_state
Definition: RecordPlugin.h:246
Kwave::record_method_t m_method
Definition: RecordPlugin.h:237
unsigned int m_buffers_recorded
Definition: RecordPlugin.h:273
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
QVector< float > m_trigger_value
Definition: RecordPlugin.h:279
unsigned int m_inhibit_count
Definition: RecordPlugin.h:276
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
Here is the call graph for this function:

◆ ~RecordPlugin()

Kwave::RecordPlugin::~RecordPlugin ( )
virtual

Destructor

Definition at line 92 of file RecordPlugin.cpp.

References m_decoder, m_device, m_dialog, and m_thread.

93 {
94  Q_ASSERT(!m_dialog);
95  if (m_dialog) delete m_dialog;
96  m_dialog = Q_NULLPTR;
97 
98  Q_ASSERT(!m_thread);
99  if (m_thread) delete m_thread;
100  m_thread = Q_NULLPTR;
101 
102  Q_ASSERT(!m_decoder);
103  if (m_decoder) delete m_decoder;
104  m_decoder = Q_NULLPTR;
105 
106  if (m_device) delete m_device;
107  m_device = Q_NULLPTR;
108 }
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249

Member Function Documentation

◆ buffersChanged

void Kwave::RecordPlugin::buffersChanged ( )
privateslot

restart recorder with new buffer settings

Definition at line 816 of file RecordPlugin.cpp.

Referenced by setup().

817 {
818  InhibitRecordGuard _lock(*this); // don't record while settings change
819  // this implicitly activates the new settings
820 }
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
Here is the caller graph for this function:

◆ changeBitsPerSample

void Kwave::RecordPlugin::changeBitsPerSample ( unsigned int  new_bits)
privateslot

select a new resolution [bits/sample]

Definition at line 711 of file RecordPlugin.cpp.

References Kwave::RecordDevice::bitsPerSample(), changeSampleFormat(), m_device, m_device_name, m_dialog, notice(), Kwave::RecordDialog::params(), Kwave::RecordParams::sample_format, Kwave::RecordDialog::setBitsPerSample(), Kwave::RecordDevice::setBitsPerSample(), Kwave::RecordDialog::setSupportedBits(), Kwave::RecordDevice::supportedBits(), Kwave::toInt(), and Kwave::SampleFormat::Unknown.

Referenced by changeCompression(), and setup().

712 {
713  Q_ASSERT(m_dialog);
714  if (!m_dialog) return;
715 
716  InhibitRecordGuard _lock(*this); // don't record while settings change
717 // qDebug("RecordPlugin::changeBitsPerSample(%d)", new_bits);
718 
719  if (!m_device || m_device_name.isNull()) {
720  // no device -> dummy/shortcut
723  return;
724  }
725 
726  // check the supported resolution in bits per sample
727  QList<unsigned int> supported_bits = m_device->supportedBits();
728  int bits = new_bits;
729  if (!supported_bits.contains(bits) && !supported_bits.isEmpty()) {
730  // find the nearest resolution
731  int nearest = supported_bits.last();
732  foreach (unsigned int b, supported_bits) {
733  if (qAbs(Kwave::toInt(b) - nearest) <= qAbs(bits - nearest))
734  nearest = Kwave::toInt(b);
735  }
736  bits = nearest;
737 
738  if ((Kwave::toInt(new_bits) > 0) && (bits > 0)) notice(
739  i18n("%1 bits per sample is not supported, "\
740  "using %2 bits per sample",
741  Kwave::toInt(new_bits), bits));
742  }
743  m_dialog->setSupportedBits(supported_bits);
744 
745  // try to activate the resolution
746  int err = m_device->setBitsPerSample(bits);
747  if (err < 0) {
748  // revert to the current device setting if failed
749  bits = m_device->bitsPerSample();
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",
754  Kwave::toInt(new_bits), bits));
755  }
756  m_dialog->setBitsPerSample(bits);
757 
758  // set the sample format again
760 }
void notice(QString message)
void setBitsPerSample(unsigned int bits)
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
virtual QList< unsigned int > supportedBits()=0
virtual int bitsPerSample()=0
void setSupportedBits(const QList< unsigned int > &bits)
virtual int setBitsPerSample(unsigned int new_bits)=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
Kwave::RecordParams & params()
void changeSampleFormat(Kwave::SampleFormat::Format new_format)
Kwave::SampleFormat::Format sample_format
Definition: RecordParams.h:106
Here is the call graph for this function:
Here is the caller graph for this function:

◆ changeCompression

void Kwave::RecordPlugin::changeCompression ( Kwave::Compression::Type  new_compression)
privateslot

change compression type

Definition at line 651 of file RecordPlugin.cpp.

References Kwave::RecordParams::bits_per_sample, changeBitsPerSample(), Kwave::RecordDevice::compression(), Kwave::RecordDevice::detectCompressions(), m_device, m_device_name, m_dialog, Kwave::Plugin::name(), Kwave::Compression::NONE, notice(), Kwave::RecordDialog::params(), Kwave::RecordDialog::setCompression(), Kwave::RecordDevice::setCompression(), and Kwave::RecordDialog::setSupportedCompressions().

Referenced by changeSampleRate(), and setup().

654 {
655  Q_ASSERT(m_dialog);
656  if (!m_dialog) return;
657 
658  InhibitRecordGuard _lock(*this); // don't record while settings change
659 // qDebug("RecordPlugin::changeCompression(%d)", new_compression);
660 
661  if (!m_device || m_device_name.isNull()) {
662  // no device -> dummy/shortcut
665  return;
666  }
667 
668  // check the supported compressions
669  QList<Kwave::Compression::Type> supported_comps =
671  Kwave::Compression::Type compression = new_compression;
672  if (!supported_comps.contains(compression) &&
673  (compression != Kwave::Compression::NONE))
674  {
675  // try to disable the compression (type 0)
676  compression = Kwave::Compression::NONE;
677  if (!supported_comps.isEmpty() &&
678  !supported_comps.contains(compression))
679  {
680  // what now, "None" is not supported
681  // -> take the first supported one
682  compression = supported_comps[0];
683  }
684 
685  if (compression != new_compression) {
686  const QString c1(Kwave::Compression(new_compression).name());
687  const QString c2(Kwave::Compression(compression).name());
688  notice(i18n("Compression '%1' not supported, using '%2'", c1, c2));
689  }
690  }
691  m_dialog->setSupportedCompressions(supported_comps);
692 
693  // try to activate the new compression
694  int err = m_device->setCompression(compression);
695  if (err < 0) {
696  // revert to the current device setting if failed
697  if (compression != m_device->compression()) {
698  const QString c1(Kwave::Compression(compression).name());
699  const QString c2(Kwave::Compression(m_device->compression()).name());
700  notice(i18n("Compression '%1' failed, using '%2'.", c1 ,c2));
701  }
702  compression = m_device->compression();
703  }
704  m_dialog->setCompression(compression);
705 
706  // set the resolution in bits per sample again
708 }
void notice(QString message)
unsigned int bits_per_sample
Definition: RecordParams.h:105
void changeBitsPerSample(unsigned int new_bits)
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
virtual QString name() const
Definition: Plugin.cpp:196
virtual int setCompression(Kwave::Compression::Type new_compression)=0
void setCompression(int compression)
virtual QList< Kwave::Compression::Type > detectCompressions()=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
virtual Kwave::Compression::Type compression()=0
Kwave::RecordParams & params()
void setSupportedCompressions(const QList< Kwave::Compression::Type > &comps)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ changeSampleFormat

void Kwave::RecordPlugin::changeSampleFormat ( Kwave::SampleFormat::Format  new_format)
privateslot

select a new sample format

Definition at line 763 of file RecordPlugin.cpp.

References Kwave::TypesMap< IDX, DATA >::description(), Kwave::RecordDevice::detectSampleFormats(), Kwave::TypesMap< IDX, DATA >::findFromData(), m_device, m_device_name, m_dialog, notice(), Kwave::RecordDevice::sampleFormat(), Kwave::RecordDialog::setSampleFormat(), Kwave::RecordDevice::setSampleFormat(), Kwave::RecordDialog::setSupportedSampleFormats(), and Kwave::SampleFormat::Unknown.

Referenced by changeBitsPerSample(), and setup().

765 {
766  Q_ASSERT(m_dialog);
767  if (!m_dialog) return;
768 
769  InhibitRecordGuard _lock(*this); // don't record while settings change
770 
771  if (!m_device || m_device_name.isNull()) {
772  // no device -> dummy/shortcut
774  return;
775  }
776 
777  // check the supported sample formats
778  QList<Kwave::SampleFormat::Format> supported_formats =
780  Kwave::SampleFormat::Format format = new_format;
781  if (!supported_formats.contains(format) && !supported_formats.isEmpty()) {
782  // use the device default instead
783  format = m_device->sampleFormat();
784 
785  // if this was also not supported -> stupid device !?
786  if (!supported_formats.contains(format)) {
787  format = supported_formats.first(); // just take the first one :-o
788  }
789 
791  const QString s1 = sf.description(sf.findFromData(new_format), true);
792  const QString s2 = sf.description(sf.findFromData(format), true);
793  if (!(new_format == -1) && !(new_format == format)) {
794  notice(i18n("Sample format '%1' is not supported, "\
795  "using '%2'", s1, s2));
796  }
797  }
798  m_dialog->setSupportedSampleFormats(supported_formats);
799 
800  // try to activate the new format
801  int err = m_device->setSampleFormat(format);
802  if (err < 0) {
803  // use the device default instead
804  format = m_device->sampleFormat();
805 
807  const QString s1 = sf.description(sf.findFromData(new_format), true);
808  const QString s2 = sf.description(sf.findFromData(format), true);
809  if (format > 0) notice(
810  i18n("Sample format '%1' failed, using '%2'", s1, s2));
811  }
812  m_dialog->setSampleFormat(format);
813 }
void notice(QString message)
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
QString description(IDX type, bool localized) const
Definition: TypesMap.h:128
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
virtual QList< Kwave::SampleFormat::Format > detectSampleFormats()=0
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
void setSampleFormat(Kwave::SampleFormat::Format sample_format)
virtual Kwave::SampleFormat::Format sampleFormat()=0
virtual int setSampleFormat(Kwave::SampleFormat::Format new_format)=0
void setSupportedSampleFormats(const QList< Kwave::SampleFormat::Format > &formats)
IDX findFromData(const DATA &data) const
Definition: TypesMap.h:89
Here is the call graph for this function:
Here is the caller graph for this function:

◆ changeSampleRate

void Kwave::RecordPlugin::changeSampleRate ( double  new_rate)
privateslot

select a new sample rate [samples/second]

Definition at line 590 of file RecordPlugin.cpp.

References changeCompression(), Kwave::RecordParams::compression, Kwave::RecordDevice::detectSampleRates(), Kwave::Compression::INVALID, m_device, m_device_name, m_dialog, notice(), Kwave::RecordDialog::params(), Kwave::RecordDialog::rate2string(), Kwave::RecordDevice::sampleRate(), Kwave::RecordDialog::setSampleRate(), Kwave::RecordDevice::setSampleRate(), Kwave::RecordDialog::setSupportedSampleRates(), and Kwave::toInt().

Referenced by changeTracks(), and setup().

591 {
592  Q_ASSERT(m_dialog);
593  if (!m_dialog) return;
594 
595  InhibitRecordGuard _lock(*this); // don't record while settings change
596 // qDebug("RecordPlugin::changeSampleRate(%u)", Kwave::toInt(new_rate));
597 
598  if (!m_device || m_device_name.isNull()) {
599  // no device -> dummy/shortcut
602  return;
603  }
604 
605  // check the supported sample rates
606  QList<double> supported_rates = m_device->detectSampleRates();
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()) {
612  // find the nearest sample rate
613  double nearest = supported_rates.last();
614  foreach (double r, supported_rates) {
615  if (fabs(r - rate) <= fabs(nearest - rate))
616  nearest = r;
617  }
618  rate = nearest;
619 
620  const QString sr1(m_dialog->rate2string(new_rate));
621  const QString sr2(m_dialog->rate2string(rate));
622  if ((Kwave::toInt(new_rate) > 0) &&
623  (Kwave::toInt(rate) > 0) &&
624  (Kwave::toInt(new_rate) != Kwave::toInt(rate)))
625  notice(i18n("%1 Hz is not supported, "\
626  "using %2 Hz", sr1, sr2));
627  }
628  m_dialog->setSupportedSampleRates(supported_rates);
629 
630  // try to activate the new sample rate
631  int err = m_device->setSampleRate(rate);
632  if (err < 0) {
633  // revert to the current device setting if failed
634  rate = m_device->sampleRate();
635  if (rate < 0) rate = 0;
636 
637  const QString sr1(m_dialog->rate2string(new_rate));
638  const QString sr2(m_dialog->rate2string(rate));
639  if ((Kwave::toInt(new_rate) > 0) &&
640  (Kwave::toInt(rate) > 0) &&
641  (Kwave::toInt(new_rate) != Kwave::toInt(rate)))
642  notice(i18n("%1 Hz failed, using %2 Hz", sr1, sr2));
643  }
644  m_dialog->setSampleRate(rate);
645 
646  // set the compression again
648 }
void notice(QString message)
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
QString rate2string(double rate) const
virtual int setSampleRate(double &new_rate)=0
void changeCompression(Kwave::Compression::Type new_compression)
virtual QList< double > detectSampleRates()=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
virtual double sampleRate()=0
void setSupportedSampleRates(const QList< double > &rates)
void setSampleRate(double new_rate)
Kwave::RecordParams & params()
Kwave::Compression::Type compression
Definition: RecordParams.h:104
Here is the call graph for this function:
Here is the caller graph for this function:

◆ changeTracks

void Kwave::RecordPlugin::changeTracks ( unsigned int  new_tracks)
privateslot

select a new number of tracks (channels)

Definition at line 508 of file RecordPlugin.cpp.

References changeSampleRate(), Kwave::RecordDevice::detectTracks(), m_device, m_device_name, m_dialog, notice(), Kwave::RecordDialog::params(), Kwave::RecordParams::sample_rate, Kwave::RecordDialog::setSupportedTracks(), Kwave::RecordDialog::setTracks(), Kwave::RecordDevice::setTracks(), and Kwave::RecordDevice::tracks().

Referenced by setDevice(), and setup().

509 {
510  Q_ASSERT(m_dialog);
511  if (!m_dialog) return;
512 
513  InhibitRecordGuard _lock(*this); // don't record while settings change
514 // qDebug("RecordPlugin::changeTracks(%u)", new_tracks);
515 
516  if (!m_device || m_device_name.isNull()) {
517  // no device -> dummy/shortcut
519  m_dialog->setTracks(0);
520  changeSampleRate(0);
521  return;
522  }
523 
524  // check the supported tracks
525  unsigned int min = 0;
526  unsigned int max = 0;
527  if ((m_device->detectTracks(min, max) < 0) || (max < 1))
528  min = max = 0;
529  if (min > max) min = max;
530 
531  unsigned int channels = new_tracks;
532  if ((channels < min) || (channels > max)) {
533  // clip to the supported number of tracks
534  if (channels < min) channels = min;
535  if (channels > max) channels = max;
536  qDebug("RecordPlugin::changeTracks(%u) -> clipped to %u",
537  new_tracks, channels);
538 
539  if ((new_tracks && channels) && (new_tracks != channels)) {
540  QString s1;
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;
545  default:
546  s1 = i18n("%1 channels", new_tracks);
547  }
548  QString s2;
549  switch (channels) {
550  case 1: s2 = i18n("Mono"); break;
551  case 2: s2 = i18n("Stereo"); break;
552  case 4: s2 = i18n("Quadro"); break;
553  default:
554  s2 = i18n("%1 channels", channels);
555  }
556 
557  notice(i18n("%1 is not supported, using %2", s1, s2));
558  }
559  }
560  Q_ASSERT(channels >= min);
561  Q_ASSERT(channels <= max);
562  m_dialog->setSupportedTracks(min, max);
563 
564  // try to activate the new number of tracks
565  int err = m_device->setTracks(channels);
566  if (err < 0) {
567  // revert to the current device setting if failed
568  int t = m_device->tracks();
569  if (t > 0) {
570  // current device state seems to be valid
571  channels = t;
572  if (channels < min) channels = min;
573  if (channels > max) channels = max;
574  } else {
575  // current device state is invalid
576  channels = 0;
577  }
578 
579  if (new_tracks && (channels > 0)) notice(
580  i18n("Recording with %1 channel(s) failed, "\
581  "using %2 channel(s)", new_tracks, channels));
582  }
583  m_dialog->setTracks(channels);
584 
585  // activate the new sample rate
587 }
void notice(QString message)
void setTracks(unsigned int tracks)
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
virtual int setTracks(unsigned int &tracks)=0
virtual int detectTracks(unsigned int &min, unsigned int &max)=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
void changeSampleRate(double new_rate)
void setSupportedTracks(unsigned int min, unsigned int max)
Kwave::RecordParams & params()
virtual int tracks()=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ checkTrigger()

bool Kwave::RecordPlugin::checkTrigger ( unsigned int  track,
const Kwave::SampleArray buffer 
)
private

check if the trigger level has been reached

Parameters
trackindex of the track that is checked
bufferarray with Kwave sample data
Returns
true if trigger reached or no trigger set

Definition at line 1314 of file RecordPlugin.cpp.

References m_dialog, m_trigger_value, m_writers, Kwave::RecordDialog::params(), Kwave::RecordParams::record_trigger, Kwave::RecordParams::record_trigger_enabled, sample2float(), Kwave::RecordParams::sample_rate, Kwave::SampleArray::size(), Kwave::RecordParams::start_time, Kwave::RecordParams::start_time_enabled, Kwave::toInt(), and Kwave::MultiTrackSink< SINK, INITIALIZE >::tracks().

Referenced by processBuffer().

1316 {
1317  Q_ASSERT(m_dialog);
1318  if (!m_dialog) return false;
1319 
1320  // check if the recording start time has been reached
1322  if (QDateTime::currentDateTime() < m_dialog->params().start_time)
1323  return false;
1324  }
1325 
1326  // shortcut if no trigger has been set
1327  if (!m_dialog->params().record_trigger_enabled) return true;
1328 
1329  // check the input parameters
1330  if (!buffer.size()) return false;
1331  if (!m_writers) return false;
1332  if (m_trigger_value.size() != Kwave::toInt(m_writers->tracks()))
1333  return false;
1334 
1335  // pass the buffer through a rectifier and a lowpass with
1336  // center frequency about 2Hz to get the amplitude
1337  float trigger = static_cast<float>(
1338  m_dialog->params().record_trigger / 100.0);
1339  const float rate = static_cast<const float>(
1341 
1342  /*
1343  * simple lowpass calculation:
1344  *
1345  * 1 + z
1346  * H(z) = a0 * ----------- | z = e ^ (j*2*pi*f)
1347  * z + b1
1348  *
1349  * 1 1 - n
1350  * a0 = ----- b1 = --------
1351  * 1 + n 1 + n
1352  *
1353  * Fg = fg / fa
1354  *
1355  * n = cot(Pi * Fg)
1356  *
1357  * y[t] = a0 * x[t] + a1 * x[t-1] - b1 * y[t-1]
1358  *
1359  */
1360 
1361  // rise coefficient: ~20Hz
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);
1367 
1368  // fall coefficient: ~1.0Hz
1369  const float f_fall = 1.0f;
1370  Fg = f_fall / rate;
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);
1374 
1375  float y = m_trigger_value[track];
1376  float last_x = y;
1377  for (unsigned int t = 0; t < buffer.size(); ++t) {
1378  float x = fabsf(sample2float(buffer[t])); /* rectifier */
1379 
1380  if (x > y) { /* diode */
1381  // rise if amplitude is above average (serial R)
1382  y = (a0_r * x) + (a0_r * last_x) - (b1_r * y);
1383  }
1384 
1385  // fall (parallel R)
1386  y = (a0_f * x) + (a0_f * last_x) - (b1_f * y);
1387 
1388  // remember x[t-1]
1389  last_x = x;
1390 
1391 // nice for debugging:
1392 // buffer[t] = (int)((double)(1 << (SAMPLE_BITS-1)) * y);
1393  if (y > trigger) return true;
1394  }
1395  m_trigger_value[track] = y;
1396 
1397  qDebug(">> level=%5.3g, trigger=%5.3g", y, trigger);
1398 
1399  return false;
1400 }
virtual unsigned int tracks() const Q_DECL_OVERRIDE
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
QVector< float > m_trigger_value
Definition: RecordPlugin.h:279
unsigned int record_trigger
Definition: RecordParams.h:87
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
static float sample2float(const sample_t s)
Definition: Sample.h:65
Kwave::RecordParams & params()
unsigned int size() const
QDateTime start_time
Definition: RecordParams.h:84
Here is the call graph for this function:
Here is the caller graph for this function:

◆ closeDevice()

void Kwave::RecordPlugin::closeDevice ( )
private

close m_device and delete it

Definition at line 261 of file RecordPlugin.cpp.

References Kwave::RecordDevice::close(), m_device, and m_retry_timer.

262 {
263  if (m_retry_timer.isActive()) m_retry_timer.stop();
264 
265  if (m_device) {
266  m_device->close();
267  delete m_device;
268  m_device = Q_NULLPTR;
269  }
270 }
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
virtual int close()=0
Here is the call graph for this function:

◆ enqueuePrerecording()

void Kwave::RecordPlugin::enqueuePrerecording ( unsigned int  track,
const Kwave::SampleArray decoded 
)
private

Enqueue a buffer with decoded samples into a prerecording buffer of the corresponding track.

Parameters
trackindex of the track [0...tracks-1]
decodedarray with decoded samples, in Kwave's internal format

Definition at line 1403 of file RecordPlugin.cpp.

References m_dialog, m_prerecording_queue, and Kwave::toInt().

Referenced by processBuffer().

1405 {
1406  Q_ASSERT(m_dialog);
1407  Q_ASSERT(Kwave::toInt(track) < m_prerecording_queue.size());
1408  if (!m_dialog) return;
1409  if (Kwave::toInt(track) >= m_prerecording_queue.size()) return;
1410 
1411  // append the array with decoded sample to the prerecording buffer
1412  m_prerecording_queue[track].put(decoded);
1413 }
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
Here is the call graph for this function:
Here is the caller graph for this function:

◆ enterInhibit()

void Kwave::RecordPlugin::enterInhibit ( )
protected

inhibits recording, stopping the recorder if necessary

Definition at line 823 of file RecordPlugin.cpp.

References m_inhibit_count, m_thread, processBuffer(), Kwave::RecordThread::queuedBuffers(), and Kwave::WorkerThread::stop().

Referenced by Kwave::RecordPlugin::InhibitRecordGuard::InhibitRecordGuard().

824 {
825  m_inhibit_count++;
826  if ((m_inhibit_count == 1) && m_thread) {
827  // set hourglass cursor
828  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
829 
830 // qDebug("RecordPlugin::enterInhibit() - STOPPING");
831  m_thread->stop();
832  Q_ASSERT(!m_thread->isRunning());
833 
834  // de-queue all buffers that are still in the queue
835  while (m_thread->queuedBuffers())
836  processBuffer();
837  }
838 }
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
unsigned int m_inhibit_count
Definition: RecordPlugin.h:276
unsigned int queuedBuffers()
virtual int stop(unsigned int timeout=10000)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ flushPrerecordingQueue()

void Kwave::RecordPlugin::flushPrerecordingQueue ( )
private

Flush the content of the prerecording queue to the output

See also
m_writers

Definition at line 1416 of file RecordPlugin.cpp.

References Kwave::StreamObject::blockSize(), Kwave::SampleFIFO::crop(), Kwave::SampleFIFO::flush(), Kwave::SampleFIFO::get(), Kwave::SampleFIFO::length(), m_controller, m_decoder, m_dialog, m_prerecording_queue, m_thread, m_writers, Kwave::RecordDialog::params(), Kwave::RecordController::setEmpty(), Kwave::MultiTrackSink< SINK, INITIALIZE >::tracks(), Kwave::RecordParams::tracks, and Kwave::Writer::write().

Referenced by processBuffer().

1417 {
1418  if (!m_prerecording_queue.size()) return;
1419  Q_ASSERT(m_dialog);
1420  Q_ASSERT(m_thread);
1421  Q_ASSERT(m_decoder);
1422  if (!m_dialog || !m_thread || !m_decoder) return;
1423 
1424  const Kwave::RecordParams &params = m_dialog->params();
1425  const unsigned int tracks = params.tracks;
1426  Q_ASSERT(tracks);
1427  if (!tracks) return;
1428  Q_ASSERT(m_writers);
1429  if (!m_writers) return;
1430  Q_ASSERT(tracks == m_writers->tracks());
1431  if (!tracks || (tracks != m_writers->tracks())) return;
1432 
1433  for (unsigned int track=0; track < tracks; ++track) {
1434  Kwave::SampleFIFO &fifo = m_prerecording_queue[track];
1435  Q_ASSERT(fifo.length());
1436  if (!fifo.length()) continue;
1437  fifo.crop(); // enforce the correct size
1438 
1439  // push all buffers to the writer, starting at the tail
1440  Kwave::Writer *writer = (*m_writers)[track];
1441  Q_ASSERT(writer);
1442  if (writer) {
1443  Kwave::SampleArray buffer(writer->blockSize());
1444  unsigned int rest = fifo.length();
1445  while (rest) {
1446  unsigned int read = fifo.get(buffer);
1447  if (read < 1) break;
1448  writer->write(buffer, read);
1449  rest -= read;
1450  }
1451  } else {
1452  // fallback: discard the FIFO content
1453  fifo.flush();
1454  }
1455  Q_ASSERT(fifo.length() == 0);
1456  }
1457 
1458  // the queues are no longer needed
1459  m_prerecording_queue.clear();
1460 
1461  // we have transferred data to the writers, we are no longer empty
1462  m_controller.setEmpty(false);
1463 }
virtual unsigned int tracks() const Q_DECL_OVERRIDE
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
virtual bool write(const Kwave::SampleArray &buffer, unsigned int &count)=0
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
virtual unsigned int get(Kwave::SampleArray &buffer)
Definition: SampleFIFO.cpp:70
unsigned int tracks
Definition: RecordParams.h:102
virtual void crop()
Definition: SampleFIFO.cpp:136
virtual unsigned int length()
Definition: SampleFIFO.cpp:122
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
virtual void flush()
Definition: SampleFIFO.cpp:45
virtual unsigned int blockSize() const
Kwave::RecordParams & params()
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
Here is the call graph for this function:
Here is the caller graph for this function:

◆ leaveInhibit()

void Kwave::RecordPlugin::leaveInhibit ( )
protected

leave the area with recording inhibited, restart recorder if needed

Definition at line 841 of file RecordPlugin.cpp.

References m_dialog, m_inhibit_count, m_thread, paramsValid(), setupRecordThread(), and Kwave::WorkerThread::start().

Referenced by Kwave::RecordPlugin::InhibitRecordGuard::~InhibitRecordGuard().

842 {
843  Q_ASSERT(m_inhibit_count);
844  Q_ASSERT(m_dialog);
845 
847 
848  while (!m_inhibit_count && paramsValid()) {
849 // qDebug("RecordPlugin::leaveInhibit() - STARTING ("
850 // "%d channels, %d bits)",
851 // m_dialog->params().tracks,
852 // m_dialog->params().bits_per_sample);
853 
854  Q_ASSERT(!m_thread->isRunning());
855  if (m_thread->isRunning()) break;
856 
857  // set new parameters for the recorder
859 
860  // and let the thread run (again)
861  m_thread->start();
862  break;
863  }
864 
865  // take back the hourglass cursor
866  if (!m_inhibit_count) QApplication::restoreOverrideCursor();
867 }
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
unsigned int m_inhibit_count
Definition: RecordPlugin.h:276
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
virtual void start()
Here is the call graph for this function:
Here is the caller graph for this function:

◆ notice()

void Kwave::RecordPlugin::notice ( QString  message)
private

show a short notice which disappears automatically, e.g. if something is not supported and has been substituted

Parameters
messagethe notice that should pop up

Definition at line 254 of file RecordPlugin.cpp.

References m_dialog, and Kwave::RecordDialog::message().

Referenced by changeBitsPerSample(), changeCompression(), changeSampleFormat(), changeSampleRate(), changeTracks(), setDevice(), and setupRecordThread().

255 {
256  Q_ASSERT(m_dialog);
257  if (m_dialog) m_dialog->message(message);
258 }
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
void message(const QString &message)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ paramsValid()

bool Kwave::RecordPlugin::paramsValid ( )
private

Returns true if all parameters are valid and the recording (thread) could be started.

Definition at line 870 of file RecordPlugin.cpp.

References Kwave::RecordDevice::bitsPerSample(), Kwave::RecordDevice::endianness(), m_device, m_device_name, m_dialog, m_thread, Kwave::RecordDialog::params(), Kwave::RecordParams::sample_format, Kwave::RecordDevice::sampleFormat(), Kwave::SampleFormat::Signed, Kwave::RecordParams::tracks, Kwave::UnknownEndian, and Kwave::SampleFormat::Unsigned.

Referenced by leaveInhibit(), setDevice(), and setupRecordThread().

871 {
872  if (!m_thread || !m_device || !m_dialog) return false;
873 
874  // check for a valid/usable record device
875  if (m_device_name.isNull()) return false;
878  return false;
879  if (m_device->bitsPerSample() < 1) return false;
880  if (m_device->endianness() == Kwave::UnknownEndian) return false;
881 
882  // check for valid parameters in the dialog
883  const Kwave::RecordParams &params = m_dialog->params();
884  if (params.tracks < 1) return false;
885  if ( (params.sample_format != Kwave::SampleFormat::Unsigned) &&
886  (params.sample_format != Kwave::SampleFormat::Signed) ) return false;
887 
888  return true;
889 }
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
virtual int bitsPerSample()=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
unsigned int tracks
Definition: RecordParams.h:102
virtual Kwave::SampleFormat::Format sampleFormat()=0
Kwave::RecordParams & params()
Kwave::SampleFormat::Format sample_format
Definition: RecordParams.h:106
virtual Kwave::byte_order_t endianness()=0
Here is the call graph for this function:
Here is the caller graph for this function:

◆ prerecordingChanged

void Kwave::RecordPlugin::prerecordingChanged ( bool  enable)
privateslot

the prerecording checkbox has changed

Definition at line 1608 of file RecordPlugin.cpp.

Referenced by setup().

1609 {
1610  (void)enable;
1611  InhibitRecordGuard _lock(*this); // activate the change
1612 }
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
Here is the caller graph for this function:

◆ processBuffer

void Kwave::RecordPlugin::processBuffer ( )
privateslot

process a raw audio buffer

Definition at line 1466 of file RecordPlugin.cpp.

References Kwave::RecordController::actionStop(), checkTrigger(), Kwave::SampleDecoder::decode(), Kwave::RecordThread::dequeue(), Kwave::RecordController::deviceBufferFull(), Kwave::RecordController::deviceTriggerReached(), enqueuePrerecording(), flushPrerecordingQueue(), Kwave::MultiWriter::last(), m_buffers_recorded, m_controller, m_decoder, m_dialog, m_prerecording_queue, m_state, m_thread, m_writers, Kwave::RecordDialog::params(), Kwave::RecordThread::queuedBuffers(), Kwave::SampleDecoder::rawBytesPerSample(), Kwave::REC_BUFFERING, Kwave::REC_DONE, Kwave::REC_EMPTY, Kwave::REC_PAUSED, Kwave::REC_PRERECORDING, Kwave::REC_RECORDING, Kwave::REC_UNINITIALIZED, Kwave::REC_WAITING_FOR_TRIGGER, Kwave::RecordParams::record_time, Kwave::RecordParams::record_time_limited, Kwave::RecordParams::record_trigger_enabled, Kwave::RecordParams::sample_rate, Kwave::RecordController::setEmpty(), sigRecordedSamples(), Kwave::SampleArray::size(), split(), Kwave::RecordParams::start_time_enabled, Kwave::toInt(), Kwave::toUint(), Kwave::MultiTrackSink< SINK, INITIALIZE >::tracks(), Kwave::RecordParams::tracks, updateBufferProgressBar(), and Kwave::RecordDialog::updateEffects().

Referenced by enterInhibit(), and setup().

1467 {
1468  bool recording_done = false;
1469 
1470  // de-queue the buffer from the thread
1471  if (!m_thread) return;
1472  if (!m_thread->queuedBuffers()) return;
1473  QByteArray buffer = m_thread->dequeue();
1474 
1475  // abort here if we have no dialog or no decoder
1476  if (!m_dialog || !m_decoder) return;
1477 
1478  // we received a buffer -> update the progress bar
1480 
1481  const Kwave::RecordParams &params = m_dialog->params();
1482  const unsigned int tracks = params.tracks;
1483  Q_ASSERT(tracks);
1484  if (!tracks) return;
1485 
1486  const unsigned int bytes_per_sample = m_decoder->rawBytesPerSample();
1487  Q_ASSERT(bytes_per_sample);
1488  if (!bytes_per_sample) return;
1489 
1490  unsigned int samples = (buffer.size() / bytes_per_sample) / tracks;
1491  Q_ASSERT(samples);
1492  if (!samples) return;
1493 
1494  // check for reached recording time limit if enabled
1495  if (params.record_time_limited && m_writers) {
1496  const sample_index_t last = m_writers->last();
1497  const sample_index_t already_recorded = (last) ? (last + 1) : 0;
1498  const sample_index_t limit = static_cast<const sample_index_t>(rint(
1499  params.record_time * params.sample_rate));
1500  if (already_recorded + samples >= limit) {
1501  // reached end of recording time, we are full
1502  if (m_state == Kwave::REC_RECORDING) {
1503  samples = Kwave::toUint(
1504  (limit > already_recorded) ?
1505  (limit - already_recorded) : 0);
1506  buffer.resize(samples * tracks * bytes_per_sample);
1507  }
1508  recording_done = true;
1509  }
1510  }
1511 
1512  QByteArray buf;
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;
1516 
1517  Kwave::SampleArray decoded(samples);
1518  Q_ASSERT(decoded.size() == samples);
1519  if (decoded.size() != samples) return;
1520 
1521  // check for trigger
1522  // note: this might change the state, which affects the
1523  // processing of all tracks !
1527  {
1528  for (unsigned int track=0; track < tracks; ++track) {
1529  // split off and decode buffer with current track
1530  split(buffer, buf, bytes_per_sample, track, tracks);
1531  m_decoder->decode(buf, decoded);
1532  if (checkTrigger(track, decoded)) {
1534  break;
1535  }
1536  }
1537  }
1538 
1539  if ((m_state == Kwave::REC_RECORDING) && !m_prerecording_queue.isEmpty()) {
1540  // flush all prerecorded buffers to the output
1542  }
1543 
1544  // use a copy of the state, in case it changes below ;-)
1545  Kwave::RecordState state = m_state;
1546  for (unsigned int track=0; track < tracks; ++track) {
1547  // decode and care for all special effects, meters and so on
1548  // split off and decode buffer with current track
1549  split(buffer, buf, bytes_per_sample, track, tracks);
1550  m_decoder->decode(buf, decoded);
1551 
1552  // update the level meter and other effects
1553  m_dialog->updateEffects(track, decoded);
1554 
1555  // if the first buffer is full -> leave REC_BUFFERING
1556  // limit state transitions to a point before the first track is
1557  // processed (avoid asymmetry)
1558  if ((track == 0) && (m_state == Kwave::REC_BUFFERING) &&
1559  (m_buffers_recorded > 1))
1560  {
1562  state = m_state; // might have changed!
1563  }
1564 
1565  switch (state) {
1567  case Kwave::REC_EMPTY:
1568  case Kwave::REC_PAUSED:
1569  case Kwave::REC_DONE:
1570  case Kwave::REC_BUFFERING:
1572  // already handled before or nothing to do...
1573  break;
1575  // enqueue the buffers into a FIFO
1576  enqueuePrerecording(track, decoded);
1577  break;
1578  case Kwave::REC_RECORDING: {
1579  // put the decoded track data into the buffer
1580  if (!m_writers) break; // (could happen due to queued signal)
1581  Q_ASSERT(tracks == m_writers->tracks());
1582  if (!tracks || (tracks != m_writers->tracks())) break;
1583 
1584  Kwave::Writer *writer = (*m_writers)[track];
1585  Q_ASSERT(writer);
1586  if (writer) (*writer) << decoded;
1587  m_controller.setEmpty(false);
1588 
1589  break;
1590  }
1591  }
1592  }
1593 
1594  // update the number of recorded samples
1595  if (m_writers) emit sigRecordedSamples(m_writers->last() + 1);
1596 
1597  // if this was the last received buffer, change state
1598  if (recording_done &&
1599  (m_state != Kwave::REC_DONE) &&
1601  {
1603  }
1604 
1605 }
void split(QByteArray &raw_data, QByteArray &dest, unsigned int bytes_per_sample, unsigned int track, unsigned int tracks)
void sigRecordedSamples(sample_index_t samples_recorded)
virtual unsigned int tracks() const Q_DECL_OVERRIDE
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
void enqueuePrerecording(unsigned int track, const Kwave::SampleArray &decoded)
virtual unsigned int rawBytesPerSample()=0
bool checkTrigger(unsigned int track, const Kwave::SampleArray &buffer)
Kwave::RecordState m_state
Definition: RecordPlugin.h:246
unsigned int m_buffers_recorded
Definition: RecordPlugin.h:273
quint64 sample_index_t
Definition: Sample.h:28
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
virtual sample_index_t last() const
Definition: MultiWriter.cpp:85
unsigned int record_time
Definition: RecordParams.h:81
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
unsigned int tracks
Definition: RecordParams.h:102
virtual void decode(QByteArray &raw_data, Kwave::SampleArray &decoded)=0
QByteArray dequeue()
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
unsigned int queuedBuffers()
Kwave::RecordParams & params()
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
unsigned int toUint(T x)
Definition: Utils.h:109
void updateEffects(unsigned int track, Kwave::SampleArray &buffer)
RecordState
Definition: RecordState.h:25
Here is the call graph for this function:
Here is the caller graph for this function:

◆ recordStopped

void Kwave::RecordPlugin::recordStopped ( int  reason)
protectedslot

called when the recording stopped (for detecting aborts only)

Definition at line 1086 of file RecordPlugin.cpp.

References Kwave::MessageBox::error(), Kwave::MultiWriter::flush(), Kwave::MultiWriter::last(), m_dialog, m_prerecording_queue, m_writers, Kwave::RecordDialog::params(), Kwave::SignalManager::setFileInfo(), Kwave::FileInfo::setLength(), Kwave::FileInfo::setTracks(), Kwave::Plugin::signalLength(), Kwave::Plugin::signalManager(), and Kwave::RecordParams::tracks.

Referenced by setup().

1087 {
1088  qDebug("RecordPlugin::recordStopped(%d)", reason);
1089  if (reason >= 0) return; // nothing to do
1090 
1091  // recording was aborted
1092  QString err_msg;
1093  switch (reason) {
1094  case -ENOBUFS:
1095  err_msg = i18n("Buffer overrun. Please increase the "\
1096  "number and/or size of the record buffers.");
1097  break;
1098  case -EBUSY:
1099  err_msg = i18n("The recording device seems to be busy.");
1100  break;
1101  default:
1102  err_msg = i18n("Reading from the recording device failed. "\
1103  "Error number = %1 (%2)", -reason,
1104  QString::fromLocal8Bit(strerror(-reason)));
1105  }
1107 
1108  if (m_writers) m_writers->flush();
1109  qDebug("RecordPlugin::recordStopped(): last=%lu",
1110  static_cast<unsigned long int>(
1111  (m_writers) ? m_writers->last() : 0));
1112 
1113  // flush away all prerecording buffers
1114  m_prerecording_queue.clear();
1115 
1116  // update the file info if we recorded something
1117  // NOTE: this implicitly sets the "modified" flag of the signal
1118  if (m_writers && m_writers->last()) {
1119  Kwave::FileInfo info(signalManager().metaData());
1120  info.setLength(signalLength());
1121  info.setTracks(m_dialog->params().tracks);
1122  signalManager().setFileInfo(info, false);
1123  }
1124 
1125 }
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
virtual sample_index_t last() const
Definition: MultiWriter.cpp:85
void setFileInfo(const Kwave::FileInfo &new_info, bool with_undo)
virtual void flush()
static int error(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:126
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
unsigned int tracks
Definition: RecordParams.h:102
virtual sample_index_t signalLength()
Definition: Plugin.cpp:462
Kwave::RecordParams & params()
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
Here is the call graph for this function:
Here is the caller graph for this function:

◆ resetRecording

void Kwave::RecordPlugin::resetRecording ( bool &  accepted)
protectedslot

command for resetting all recorded stuff for starting again

Parameters
acceptedbool variable that will show if the action was performed or aborted (not accepted)

Definition at line 892 of file RecordPlugin.cpp.

References _, Kwave::MultiWriter::clear(), Kwave::Plugin::emitCommand(), Kwave::SignalManager::isEmpty(), m_buffers_recorded, m_controller, m_writers, Kwave::Plugin::manager(), Kwave::Plugin::migrateToActiveContext(), Kwave::RecordController::setEmpty(), Kwave::PluginManager::signalManager(), and sigRecordedSamples().

Referenced by setup().

893 {
894  InhibitRecordGuard _lock(*this);
895 
896  if (m_writers) m_writers->clear();
897 
898  emitCommand(_("nomacro:close()"));
899  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
900  accepted = manager().signalManager().isEmpty();
901  if (!accepted) return;
902 
903  // the parent context might have changed, maybe we have to
904  // re-parent this plugin instance!
906 
907  m_buffers_recorded = 0;
908 
909  m_controller.setEmpty(true);
910  emit sigRecordedSamples(0);
911 }
void sigRecordedSamples(sample_index_t samples_recorded)
void emitCommand(const QString &command)
Definition: Plugin.cpp:510
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
virtual void migrateToActiveContext()
Definition: Plugin.cpp:516
unsigned int m_buffers_recorded
Definition: RecordPlugin.h:273
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
Kwave::PluginManager & manager() const
Definition: Plugin.cpp:437
Kwave::SignalManager & signalManager()
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
#define _(m)
Definition: memcpy.c:66
virtual void clear() Q_DECL_OVERRIDE
Definition: MultiWriter.cpp:97
Here is the call graph for this function:
Here is the caller graph for this function:

◆ retryOpen

void Kwave::RecordPlugin::retryOpen ( )
privateslot

try to open the record device, in case it was busy before

Definition at line 377 of file RecordPlugin.cpp.

References m_device_name, and setDevice().

Referenced by RecordPlugin().

378 {
379  qDebug("RecordPlugin::retryOpen()");
381 }
void setDevice(const QString &device)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setDevice

void Kwave::RecordPlugin::setDevice ( const QString &  device)
privateslot

select a new record device

Definition at line 384 of file RecordPlugin.cpp.

References _, changeTracks(), DBG, m_controller, m_device, m_device_name, m_dialog, m_method, m_retry_timer, Kwave::Plugin::name(), notice(), Kwave::RecordDevice::open(), OPEN_RETRY_TIME, Kwave::RecordDialog::params(), paramsValid(), Kwave::Plugin::parentWidget(), Kwave::RecordDialog::setDevice(), Kwave::RecordController::setInitialized(), Kwave::RecordDialog::showDevicePage(), Kwave::MessageBox::sorry(), Kwave::RecordDevice::supportedDevices(), and Kwave::RecordParams::tracks.

Referenced by retryOpen(), setMethod(), and setup().

385 {
386  Q_ASSERT(m_dialog);
387  Q_ASSERT(m_device);
388  if (!m_dialog || !m_device) return;
389 
390  InhibitRecordGuard _lock(*this); // don't record while settings change
391  qDebug("RecordPlugin::setDevice('%s')", DBG(device));
392 
393  if (m_retry_timer.isActive()) m_retry_timer.stop();
394 
395  // select the default device if this one is not supported
396  QString dev = device;
397  QStringList supported = m_device->supportedDevices();
398  if (!supported.isEmpty() && !supported.contains(device)) {
399  // use the first entry as default
400  dev = supported.first();
401  qDebug("RecordPlugin::setDevice(%s) -> fallback to '%s'",
402  DBG(device), DBG(dev));
403  }
404 
405  // if there was no valid device name, fall back to default device
406  if (dev.startsWith(_("#"))) {
407  dev = _("/dev/dsp");
408  qDebug("RecordPlugin::setDevice(%s) -> no valid device, using '%s'",
409  DBG(device), DBG(dev));
410  }
411 
412  // open and initialize the device
413  QString result = m_device->open(dev);
414 
415  // set the device in the dialog
416  m_device_name = dev;
417  m_dialog->setDevice(dev);
418 
419  // remember the device selection, just for the GUI
420  // for the next change in the method
421  QString section = _("plugin ") + name();
422  KConfigGroup cfg = KSharedConfig::openConfig()->group(section);
423  cfg.writeEntry(_("last_device_%1").arg(
424  static_cast<int>(m_method)), m_device_name);
425 // qDebug(">>> %d -> '%s'", static_cast<int>(m_method), DBG(m_device_name));
426  cfg.sync();
427 
428  if (!result.isNull()) {
429  bool shouldRetry = false;
430 
431  qWarning("RecordPlugin::setDevice('%s'): "
432  "opening the device failed. error message='%s'",
433  DBG(device), DBG(result));
434 
436 
437  if (m_device_name.length()) {
438  // build a short device name for showing to the user
439  QString short_device_name = m_device_name;
440  if (m_device_name.contains(_("|"))) {
441  // tree syntax: extract card + device
442  short_device_name = m_device_name.section(_("|"), 0, 0);
443  if (m_device_name.section(_("|"), 3, 3).length())
444  short_device_name += _(", ") +
445  m_device_name.section(_("|"), 3, 3);
446  }
447 
448  bool errIsNumeric = false;
449  int errNumber = result.toInt(&errIsNumeric);
450  if (errIsNumeric) {
451  if (errNumber == ENODEV) {
452  result = i18n(
453  "Maybe your system lacks support for the "\
454  "corresponding hardware or the hardware is not "\
455  "connected."
456  );
457  } else if (errNumber == EBUSY) {
458  result = i18n(
459  "The audio device seems to be occupied by another "\
460  "application. Retrying..."
461  );
462  shouldRetry = true;
463  } else {
464  result = i18n(
465  "Some unexpected error happened (%1). "\
466  "You may try an other recording method or "\
467  "recording device.",
468  QString::fromLocal8Bit(strerror(errNumber))
469  );
470  }
471  }
472 
473  if (result.length()) {
474  if (shouldRetry) {
475  notice(result);
476  } else {
479  result, i18nc("%1 = a device name",
480  "Unable to open the recording device (%1)",
481  short_device_name));
482  }
483  }
484  }
485 
486  if (shouldRetry) {
487  // retry later...
489  } else {
490  m_device_name = QString();
491  changeTracks(0);
492  }
493  } else {
495  }
496 
497  if (paramsValid()) {
499  } else {
500  qDebug("RecordPlugin::setDevice('%s') failed, "
501  "returning to 'UNINITIALIZED'", DBG(device));
503  }
504 
505 }
void notice(QString message)
virtual QString open(const QString &dev)=0
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
QWidget * parentWidget() const
Definition: Plugin.cpp:450
void changeTracks(unsigned int new_tracks)
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
virtual QString name() const
Definition: Plugin.cpp:196
Kwave::record_method_t m_method
Definition: RecordPlugin.h:237
virtual QStringList supportedDevices()=0
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
#define OPEN_RETRY_TIME
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
unsigned int tracks
Definition: RecordParams.h:102
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
Kwave::RecordParams & params()
#define _(m)
Definition: memcpy.c:66
void setDevice(const QString &device)
#define DBG(qs)
Definition: String.h:55
void setInitialized(bool initialized)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setMethod

void Kwave::RecordPlugin::setMethod ( Kwave::record_method_t  method)
privateslot

Change the recording method

Parameters
methodthe new recording method

Definition at line 273 of file RecordPlugin.cpp.

References _, Kwave::RecordDevice::fileFilter(), m_device, m_device_name, m_dialog, m_method, Kwave::Plugin::name(), Kwave::RECORD_ALSA, Kwave::RECORD_INVALID, Kwave::RECORD_NONE, Kwave::RECORD_OSS, Kwave::RECORD_PULSEAUDIO, Kwave::RECORD_QT, setDevice(), Kwave::RecordDialog::setFileFilter(), Kwave::RecordDialog::setMethod(), Kwave::RecordDialog::setSupportedDevices(), and Kwave::RecordDevice::supportedDevices().

Referenced by setup().

274 {
275  Q_ASSERT(m_dialog);
276  if (!m_dialog) return;
277 
278  InhibitRecordGuard _lock(*this); // don't record while settings change
279  qDebug("RecordPlugin::setMethod(%d)", static_cast<int>(method));
280 
281  // change the recording method (class RecordDevice)
282  if ((method != m_method) || !m_device) {
283  if (m_device) delete m_device;
284  m_device = Q_NULLPTR;
285  bool searching = false;
286 
287  // use the previous device
288  QString section = _("plugin ") + name();
289  KConfigGroup cfg = KSharedConfig::openConfig()->group(section);
290 
291  // restore the previous device
292  QString device = cfg.readEntry(
293  _("last_device_%1").arg(static_cast<int>(method)));
294 // qDebug("<<< %d -> '%s'", static_cast<int>(method), device.data());
295  m_device_name = device;
296 
297  do {
298  switch (method) {
299 #ifdef HAVE_OSS_SUPPORT
300  case Kwave::RECORD_OSS:
301  m_device = new Kwave::RecordOSS();
302  Q_ASSERT(m_device);
303  break;
304 #endif /* HAVE_OSS_SUPPORT */
305 
306 #ifdef HAVE_ALSA_SUPPORT
307  case Kwave::RECORD_ALSA:
308  m_device = new Kwave::RecordALSA();
309  Q_ASSERT(m_device);
310  break;
311 #endif /* HAVE_ALSA_SUPPORT */
312 
313 #ifdef HAVE_PULSEAUDIO_SUPPORT
316  Q_ASSERT(m_device);
317  break;
318 #endif /* HAVE_PULSEAUDIO_SUPPORT */
319 
320 #ifdef HAVE_QT_AUDIO_SUPPORT
321  case Kwave::RECORD_QT:
322  m_device = new Kwave::RecordQt();
323  Q_ASSERT(m_device);
324  break;
325 #endif /* HAVE_QT_AUDIO_SUPPORT */
326  default:
327  qDebug("unsupported recording method (%d)",
328  static_cast<int>(method));
329  if (!searching) {
330  // start trying all other methods
331  searching = true;
332  method = Kwave::RECORD_NONE;
333  ++method;
334  continue;
335  } else {
336  // try next method
337  ++method;
338  }
339  qDebug("unsupported recording method - trying next (%d)",
340  static_cast<int>(method));
341  if (method != Kwave::RECORD_INVALID) continue;
342  }
343  break;
344  } while (true);
345  }
346  Q_ASSERT(m_device);
347 
348  // if we found no recording method
349  if (method == Kwave::RECORD_INVALID) {
350  qWarning("found no valid recording method");
351  }
352 
353  // take the change in the method
354  m_method = method;
355 
356  // activate the cange in the dialog
357  m_dialog->setMethod(method);
358 
359  // set list of supported devices
360  QStringList supported_devices;
361  Q_ASSERT(m_device);
362  if (m_device) supported_devices = m_device->supportedDevices();
363  m_dialog->setSupportedDevices(supported_devices);
364 
365  // set current device (again), no matter if supported or not,
366  // the dialog will take care of this.
368 
369  // check the filter for the "select..." dialog. If it is
370  // empty, the "select" dialog will be disabled
371  QString file_filter;
372  if (m_device) file_filter = m_device->fileFilter();
373  m_dialog->setFileFilter(file_filter);
374 }
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
virtual QString fileFilter()
Definition: RecordDevice.h:75
virtual QString name() const
Definition: Plugin.cpp:196
Kwave::record_method_t m_method
Definition: RecordPlugin.h:237
virtual QStringList supportedDevices()=0
void setMethod(Kwave::record_method_t method)
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
#define _(m)
Definition: memcpy.c:66
void setDevice(const QString &device)
void setSupportedDevices(QStringList devices)
void setFileFilter(const QString &filter)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup()

QStringList * Kwave::RecordPlugin::setup ( QStringList &  previous_params)
virtual
See also
Kwave::Plugin::setup()

Reimplemented from Kwave::Plugin.

Definition at line 111 of file RecordPlugin.cpp.

References _, Kwave::RecordController::actionStart(), buffersChanged(), changeBitsPerSample(), changeCompression(), changeSampleFormat(), changeSampleRate(), changeTracks(), Kwave::connect(), DBG, Kwave::PluginManager::defaultParams(), Kwave::RecordController::enablePrerecording(), Kwave::RecordController::enableTrigger(), Kwave::SignalManager::enableUndo(), m_controller, m_decoder, m_dialog, m_prerecording_queue, m_thread, Kwave::Plugin::manager(), Kwave::Plugin::name(), Kwave::Plugin::parentWidget(), prerecordingChanged(), processBuffer(), Kwave::RecordThread::queuedBuffers(), recordStopped(), resetRecording(), setDevice(), setMethod(), Kwave::RecordDialog::SETTINGS_DEFAULT, Kwave::RecordDialog::SETTINGS_FORMAT, Kwave::RecordDialog::SETTINGS_SOURCE, Kwave::Plugin::signalManager(), sigRecordedSamples(), Kwave::RecordDialog::START_RECORDING, startRecording(), stateChanged(), and Kwave::WorkerThread::stop().

112 {
114 
115  qDebug("RecordPlugin::setup(%s)", DBG(previous_params.join(_(","))));;
116 
117  // if we have only one parameter, then we got called with a specific
118  // mode, e.g. "show format settings only"
119  if (previous_params.count() == 1) {
120  const QString m = previous_params[0].toLower();
121 
122  if (m == _("format"))
124  else if (m == _("source"))
126  else if (m == _("start_now"))
128 
129  // get previous parameters for the setup dialog
130  previous_params = manager().defaultParams(name());
131  qDebug("RecordPlugin::setup(%s) - MODE=%d",
132  DBG(previous_params.join(_(","))), static_cast<int>(mode));
133  }
134 
135  // create the setup dialog
136  m_dialog = new Kwave::RecordDialog(parentWidget(), previous_params,
137  &m_controller, mode);
138  Q_ASSERT(m_dialog);
139  if (!m_dialog) return Q_NULLPTR;
140 
141  // create the lowlevel recording thread
143  Q_ASSERT(m_thread);
144  if (!m_thread) {
145  delete m_dialog;
146  m_dialog = Q_NULLPTR;
147  return Q_NULLPTR;
148  }
149 
150  // connect some signals of the setup dialog
151  connect(m_dialog, SIGNAL(sigMethodChanged(Kwave::record_method_t)),
152  this, SLOT(setMethod(Kwave::record_method_t)));
153  connect(m_dialog, SIGNAL(sigDeviceChanged(QString)),
154  this, SLOT(setDevice(QString)));
155 
156  connect(m_dialog, SIGNAL(sigTracksChanged(uint)),
157  this, SLOT(changeTracks(uint)));
158  connect(m_dialog, SIGNAL(sampleRateChanged(double)),
159  this, SLOT(changeSampleRate(double)));
160  connect(m_dialog, SIGNAL(sigCompressionChanged(Kwave::Compression::Type)),
162  connect(m_dialog, SIGNAL(sigBitsPerSampleChanged(uint)),
163  this, SLOT(changeBitsPerSample(uint)));
164  connect(m_dialog,
165  SIGNAL(sigSampleFormatChanged(Kwave::SampleFormat::Format)),
166  this,
168  connect(m_dialog, SIGNAL(sigBuffersChanged()),
169  this, SLOT(buffersChanged()));
171  m_dialog, SLOT(setRecordedSamples(sample_index_t)));
172 
173  connect(m_dialog, SIGNAL(sigTriggerChanged(bool)),
174  &m_controller, SLOT(enableTrigger(bool)));
176  m_dialog->params().record_trigger_enabled ||
177  m_dialog->params().start_time_enabled
178  );
179 
180  connect(m_dialog, SIGNAL(sigPreRecordingChanged(bool)),
181  &m_controller, SLOT(enablePrerecording(bool)));
182  connect(m_dialog, SIGNAL(sigPreRecordingChanged(bool)),
183  this, SLOT(prerecordingChanged(bool)));
184  m_controller.enablePrerecording(m_dialog->params().pre_record_enabled);
185 
186  // connect the record controller and this
187  connect(&m_controller, SIGNAL(sigReset(bool&)),
188  this, SLOT(resetRecording(bool&)));
189  connect(&m_controller, SIGNAL(sigStartRecord()),
190  this, SLOT(startRecording()));
191  connect(&m_controller, SIGNAL(sigStopRecord(int)),
192  &m_controller, SLOT(deviceRecordStopped(int)));
194  this, SLOT(stateChanged(Kwave::RecordState)));
195 
196  // connect record controller and record thread
197  connect(m_thread, SIGNAL(stopped(int)),
198  &m_controller, SLOT(deviceRecordStopped(int)));
199 
200  // connect us to the record thread
201  connect(m_thread, SIGNAL(stopped(int)),
202  this, SLOT(recordStopped(int)));
203  connect(m_thread, SIGNAL(bufferFull()),
204  this, SLOT(processBuffer()),
205  Qt::QueuedConnection);
206 
207  // dummy init -> disable format settings
208  m_dialog->setSupportedTracks(0, 0);
209 
210  // activate the recording method
211  setMethod(m_dialog->params().method);
212 
213  // directly start recording if requested
216 
217  QStringList *list = new QStringList();
218  Q_ASSERT(list);
219  if (list && (m_dialog->exec() == QDialog::Accepted)) {
220  // user has pressed "OK"
221  *list = m_dialog->params().toList();
222  } else {
223  // user pressed "Cancel"
224  if (list) delete list;
225  list = Q_NULLPTR;
226  }
227 
228  /* de-queue all buffers that are pending and remove the record thread */
229  if (m_thread) {
230  m_thread->stop();
231  while (m_thread->queuedBuffers())
232  processBuffer();
233  delete m_thread;
234  m_thread = Q_NULLPTR;
235  }
236 
237  if (m_decoder) delete m_decoder;
238  m_decoder = Q_NULLPTR;
239 
240  delete m_dialog;
241  m_dialog = Q_NULLPTR;
242 
243  // flush away all prerecording buffers
244  m_prerecording_queue.clear();
245 
246  // enable undo again if we recorded something
247  if (!signalManager().isEmpty())
249 
250  return list;
251 }
void enablePrerecording(bool enable)
void sigRecordedSamples(sample_index_t samples_recorded)
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
void changeBitsPerSample(unsigned int new_bits)
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
void prerecordingChanged(bool enable)
void recordStopped(int reason)
QWidget * parentWidget() const
Definition: Plugin.cpp:450
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
void changeTracks(unsigned int new_tracks)
virtual QString name() const
Definition: Plugin.cpp:196
quint64 sample_index_t
Definition: Sample.h:28
void resetRecording(bool &accepted)
Kwave::PluginManager & manager() const
Definition: Plugin.cpp:437
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
record_method_t
Definition: RecordParams.h:37
void changeCompression(Kwave::Compression::Type new_compression)
void setMethod(Kwave::record_method_t method)
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
void stateChanged(Kwave::RecordState state)
void changeSampleRate(double new_rate)
void enableTrigger(bool enable)
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
unsigned int queuedBuffers()
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
void changeSampleFormat(Kwave::SampleFormat::Format new_format)
#define _(m)
Definition: memcpy.c:66
void setDevice(const QString &device)
#define DBG(qs)
Definition: String.h:55
virtual int stop(unsigned int timeout=10000)
RecordState
Definition: RecordState.h:25
QStringList defaultParams(const QString &name)
Here is the call graph for this function:

◆ setupRecordThread()

void Kwave::RecordPlugin::setupRecordThread ( )
private

set up the recorder thread and record device (again)

Definition at line 914 of file RecordPlugin.cpp.

References Kwave::RecordDevice::bitsPerSample(), Kwave::RecordParams::buffer_count, Kwave::RecordParams::buffer_size, Kwave::RecordParams::compression, Kwave::RecordDevice::endianness(), m_decoder, m_device, m_dialog, m_prerecording_queue, m_thread, m_trigger_value, Kwave::Compression::NONE, notice(), Kwave::RecordDialog::params(), paramsValid(), Kwave::RecordParams::pre_record_enabled, Kwave::RecordParams::pre_record_time, Kwave::SampleDecoder::rawBytesPerSample(), Kwave::RecordParams::sample_format, Kwave::RecordParams::sample_rate, Kwave::RecordDevice::sampleFormat(), Kwave::RecordThread::setBuffers(), Kwave::RecordThread::setRecordDevice(), Kwave::SampleFormat::Signed, Kwave::MessageBox::sorry(), Kwave::WorkerThread::stop(), Kwave::toInt(), Kwave::toUint(), Kwave::RecordParams::tracks, and Kwave::SampleFormat::Unsigned.

Referenced by leaveInhibit().

915 {
916  Q_ASSERT(m_thread);
917  Q_ASSERT(m_dialog);
918  Q_ASSERT(m_device);
919  if (!paramsValid()) return;
920 
921  // stop the thread if necessary (should never happen)
922  Q_ASSERT(!m_thread->isRunning());
923  if (m_thread->isRunning()) m_thread->stop();
924  Q_ASSERT(!m_thread->isRunning());
925 
926  // delete the previous decoder
927  if (m_decoder) delete m_decoder;
928  m_decoder = Q_NULLPTR;
929 
930  // our own reference to the record parameters
931  const Kwave::RecordParams &params = m_dialog->params();
932  if (!paramsValid()) return;
933 
934  // create a decoder for the current sample format
935  switch (params.compression) {
937  switch (params.sample_format) {
938  case Kwave::SampleFormat::Unsigned: /* FALLTHROUGH */
940  // decoder for all linear formats
945  );
946  break;
947  default:
948  notice(
949  i18n("The current sample format is not supported!")
950  );
951  }
952  break;
953  default:
954  notice(
955  i18n("The current compression type is not supported!")
956  );
957  return;
958  }
959 
960  Q_ASSERT(m_decoder);
961  if (!m_decoder) {
962  Kwave::MessageBox::sorry(m_dialog, i18n("Out of memory"));
963  return;
964  }
965 
966  // set up the prerecording queues
967  m_prerecording_queue.clear();
968  if (params.pre_record_enabled) {
969  // prepare a queue for each track
970  const unsigned int prerecording_samples = Kwave::toUint(
971  rint(params.pre_record_time * params.sample_rate));
972  m_prerecording_queue.resize(params.tracks);
973  for (int i=0; i < m_prerecording_queue.size(); i++)
974  m_prerecording_queue[i].setSize(prerecording_samples);
975 
976  if (m_prerecording_queue.size() != Kwave::toInt(params.tracks)) {
977  m_prerecording_queue.clear();
978  Kwave::MessageBox::sorry(m_dialog, i18n("Out of memory"));
979  return;
980  }
981  }
982 
983  // set up the recording trigger values
984  m_trigger_value.resize(params.tracks);
985  m_trigger_value.fill(0.0);
986 
987  // set up the record thread
989  unsigned int buf_count = params.buffer_count;
990  unsigned int buf_size = params.tracks *
992  (1 << params.buffer_size);
993  m_thread->setBuffers(buf_count, buf_size);
994 }
void notice(QString message)
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
virtual unsigned int rawBytesPerSample()=0
virtual int bitsPerSample()=0
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
int setBuffers(unsigned int count, unsigned int size)
unsigned int pre_record_time
Definition: RecordParams.h:78
QVector< float > m_trigger_value
Definition: RecordPlugin.h:279
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
unsigned int tracks
Definition: RecordParams.h:102
virtual Kwave::SampleFormat::Format sampleFormat()=0
Kwave::RecordParams & params()
QVector< Kwave::SampleFIFO > m_prerecording_queue
Definition: RecordPlugin.h:264
Kwave::SampleFormat::Format sample_format
Definition: RecordParams.h:106
virtual int stop(unsigned int timeout=10000)
unsigned int toUint(T x)
Definition: Utils.h:109
Kwave::Compression::Type compression
Definition: RecordParams.h:104
unsigned int buffer_count
Definition: RecordParams.h:108
virtual Kwave::byte_order_t endianness()=0
void setRecordDevice(Kwave::RecordDevice *device)
unsigned int buffer_size
Definition: RecordParams.h:109
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sigRecordedSamples

void Kwave::RecordPlugin::sigRecordedSamples ( sample_index_t  samples_recorded)
signal

emitted to promote the recording progress to the dialog

Referenced by processBuffer(), resetRecording(), and setup().

Here is the caller graph for this function:

◆ split()

void Kwave::RecordPlugin::split ( QByteArray &  raw_data,
QByteArray &  dest,
unsigned int  bytes_per_sample,
unsigned int  track,
unsigned int  tracks 
)
private

Split off one track from a raw buffer with multiple tracks into a separate buffer

Parameters
raw_datathe raw buffer with multiple tracks
destbyte array that receives the data of the specified track
bytes_per_samplenumber of bytes for each sample
trackindex of the track to split off [1...n-1]
tracksnumber of total tracks

Definition at line 1184 of file RecordPlugin.cpp.

References saw().

Referenced by processBuffer().

1188 {
1189  unsigned int samples = raw_data.size() / bytes_per_sample / tracks;
1190 
1191 #if 0
1192  // simple sawtooth generator, based on raw data
1193  // works for up to 16 channels
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++) {
1197  int v = saw[track];
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;
1201  v >>= 8;
1202  }
1203 
1204  const int max = (1 << ((bytes_per_sample * 8) - 1)) - 1;
1205  saw[track] += max / 64;
1206  if (saw[track] >= max) saw[track] = 0;
1207  }
1208 #endif
1209 
1210  if (tracks == 1) {
1211  // this would give a 1:1 memcpy
1212  dest = raw_data;
1213  } else {
1214  switch (bytes_per_sample) {
1215  case 1: {
1216  // 1...8 bits per sample, use 8 bit pointers
1217  const quint8 *src =
1218  reinterpret_cast<const quint8 *>(raw_data.constData());
1219  quint8 *dst =
1220  reinterpret_cast<quint8 *>(dest.data());
1221  src += track;
1222  while (samples) {
1223  *dst = *src;
1224  dst++;
1225  src += tracks;
1226  samples--;
1227  }
1228  break;
1229  }
1230  case 2: {
1231  // 9...16 bits per sample, use 16 bit pointers
1232  const quint16 *src =
1233  reinterpret_cast<const quint16 *>(raw_data.constData());
1234  quint16 *dst =
1235  reinterpret_cast<quint16 *>(dest.data());
1236  src += track;
1237  while (samples) {
1238  *dst = *src;
1239  dst++;
1240  src += tracks;
1241  samples--;
1242  }
1243  break;
1244  }
1245  case 3: {
1246  // 17...24 bits per sample, use 8 bit pointers, three times
1247  const quint8 *src =
1248  reinterpret_cast<const quint8 *>(raw_data.constData());
1249  quint8 *dst =
1250  reinterpret_cast<quint8 *>(dest.data());
1251  src += track * 3;
1252  while (samples) {
1253  *(dst++) = *(src++);
1254  *(dst++) = *(src++);
1255  *(dst++) = *(src++);
1256  src += (tracks - 1) * 3;
1257  samples--;
1258  }
1259  break;
1260  }
1261  case 4: {
1262  // 24...32 bits per sample, use 32 bit pointers
1263  const quint32 *src =
1264  reinterpret_cast<const quint32 *>(raw_data.constData());
1265  quint32 *dst =
1266  reinterpret_cast<quint32 *>(dest.data());
1267  src += track;
1268  while (samples) {
1269  *dst = *src;
1270  dst++;
1271  src += tracks;
1272  samples--;
1273  }
1274  break;
1275  }
1276  case 8: {
1277  // 64 bits per sample, use 64 bit pointers
1278  const quint64 *src =
1279  reinterpret_cast<const quint64 *>(raw_data.constData());
1280  quint64 *dst =
1281  reinterpret_cast<quint64 *>(dest.data());
1282  src += track;
1283  while (samples) {
1284  *dst = *src;
1285  dst++;
1286  src += tracks;
1287  samples--;
1288  }
1289  break;
1290  }
1291  default: {
1292  // default: byte wise operation
1293  const quint8 *src =
1294  reinterpret_cast<const quint8 *>(raw_data.constData());
1295  quint8 *dst =
1296  reinterpret_cast<quint8 *>(dest.data());
1297  src += (track * bytes_per_sample);
1298  unsigned int increment = (tracks - 1) * bytes_per_sample;
1299  while (samples) {
1300  for (unsigned int b = 0; b < bytes_per_sample; b++) {
1301  *dst = *src;
1302  dst++;
1303  src++;
1304  samples--;
1305  }
1306  src += increment;
1307  }
1308  }
1309  }
1310  }
1311 }
static double saw(double param)
Definition: Functions.cpp:52
Here is the call graph for this function:
Here is the caller graph for this function:

◆ startRecording

void Kwave::RecordPlugin::startRecording ( )
protectedslot

command for starting the recording, completion is signaled with sigStarted()

Definition at line 997 of file RecordPlugin.cpp.

References _, Kwave::Append, Kwave::SignalManager::bits(), Kwave::RecordParams::bits_per_sample, Kwave::RecordParams::compression, Kwave::RecordController::deviceRecordStarted(), Kwave::SignalManager::disableUndo(), Kwave::Plugin::emitCommand(), Kwave::INF_COMPRESSION, Kwave::INF_CREATION_DATE, Kwave::INF_MIMETYPE, Kwave::INF_SAMPLE_FORMAT, Kwave::INF_SOFTWARE, m_controller, m_decoder, m_device, m_dialog, m_state, m_thread, m_writers, Kwave::Plugin::migrateToActiveContext(), Kwave::RecordDialog::params(), Kwave::SignalManager::rate(), Kwave::FileInfo::rate(), Kwave::REC_PAUSED, Kwave::RecordParams::sample_format, Kwave::RecordParams::sample_rate, Kwave::FileInfo::set(), Kwave::FileInfo::setBits(), Kwave::SignalManager::setFileInfo(), Kwave::FileInfo::setRate(), Kwave::FileInfo::setTracks(), Kwave::Plugin::signalManager(), Kwave::MessageBox::sorry(), Kwave::toInt(), Kwave::MultiTrackSink< SINK, INITIALIZE >::tracks(), Kwave::RecordParams::tracks, and Kwave::SignalManager::tracks().

Referenced by setup().

998 {
999  Q_ASSERT(m_dialog);
1000  Q_ASSERT(m_thread);
1001  Q_ASSERT(m_device);
1002  if (!m_dialog || !m_thread || !m_device) return;
1003 
1004  InhibitRecordGuard _lock(*this); // don't record while settings change
1005 
1006  if ((m_state != Kwave::REC_PAUSED) || !m_decoder) {
1007  double rate = m_dialog->params().sample_rate;
1008  unsigned int tracks = m_dialog->params().tracks;
1009  unsigned int bits = m_dialog->params().bits_per_sample;
1010 
1011  if (!tracks) return;
1012 
1013  /*
1014  * if tracks or sample rate has changed
1015  * -> start over with a new signal and new settings
1016  */
1017  if ((!m_writers) ||
1018  (m_writers->tracks() != tracks) || !qFuzzyCompare(
1019  Kwave::FileInfo(signalManager().metaData()).rate(), rate))
1020  {
1021  // create a new and empty signal
1022  emitCommand(QString(_("newsignal(0,%1,%2,%3)")).arg(
1023  rate).arg(bits).arg(tracks));
1024  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1025 
1026  // the parent context might have changed, maybe we have to
1027  // re-parent this plugin instance!
1029 
1031  if (!qFuzzyCompare(mgr.rate(), rate) || (mgr.bits() != bits) ||
1032  (mgr.tracks() != tracks))
1033  {
1034  emitCommand(_("close"));
1035  return;
1036  }
1037 
1038  // we do not need undo while recording, this would only waste undo
1039  // buffers with modified/inserted data
1041 
1042  // create a sink for our audio data
1043  if (m_writers) delete m_writers;
1044  m_writers = new(std::nothrow) Kwave::MultiTrackWriter(
1046  if ((!m_writers) || (m_writers->tracks() != tracks)) {
1047  Kwave::MessageBox::sorry(m_dialog, i18n("Out of memory"));
1048  return;
1049  }
1050  } else {
1051  // re-use the current signal and append to it
1052  }
1053 
1054  // initialize the file information
1055  Kwave::FileInfo fileInfo(signalManager().metaData());
1056  fileInfo.setRate(rate);
1057  fileInfo.setBits(bits);
1058  fileInfo.setTracks(tracks);
1059  fileInfo.set(Kwave::INF_MIMETYPE, _("audio/vnd.wave"));
1060  fileInfo.set(Kwave::INF_SAMPLE_FORMAT,
1063 
1064  // add our Kwave Software tag
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));
1070  fileInfo.set(Kwave::INF_SOFTWARE, software);
1071 
1072  // add a date tag, ISO format
1073  QDate now(QDate::currentDate());
1074  QString date;
1075  date = date.sprintf("%04d-%02d-%02d",
1076  now.year(), now.month(), now.day());
1077  fileInfo.set(Kwave::INF_CREATION_DATE, date);
1078  signalManager().setFileInfo(fileInfo, false);
1079  }
1080 
1081  // now the recording can be considered to be started
1083 }
void emitCommand(const QString &command)
Definition: Plugin.cpp:510
virtual unsigned int tracks() const Q_DECL_OVERRIDE
unsigned int bits_per_sample
Definition: RecordParams.h:105
Kwave::SampleDecoder * m_decoder
Definition: RecordPlugin.h:258
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
friend class InhibitRecordGuard
Definition: RecordPlugin.h:101
double rate() const
Definition: FileInfo.cpp:415
Kwave::RecordState m_state
Definition: RecordPlugin.h:246
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
virtual void migrateToActiveContext()
Definition: Plugin.cpp:516
unsigned int tracks()
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
void setFileInfo(const Kwave::FileInfo &new_info, bool with_undo)
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
int toInt(T x)
Definition: Utils.h:127
double rate() const
Kwave::RecordDevice * m_device
Definition: RecordPlugin.h:249
unsigned int tracks
Definition: RecordParams.h:102
Kwave::RecordController m_controller
Definition: RecordPlugin.h:243
Kwave::RecordParams & params()
Kwave::SampleFormat::Format sample_format
Definition: RecordParams.h:106
#define _(m)
Definition: memcpy.c:66
unsigned int bits() const
Kwave::Compression::Type compression
Definition: RecordParams.h:104
Here is the call graph for this function:
Here is the caller graph for this function:

◆ stateChanged

void Kwave::RecordPlugin::stateChanged ( Kwave::RecordState  state)
protectedslot

called when the recording engine has changed it's state

Definition at line 1128 of file RecordPlugin.cpp.

References Kwave::MultiWriter::flush(), m_buffers_recorded, m_dialog, m_state, m_writers, Kwave::REC_DONE, Kwave::REC_EMPTY, Kwave::REC_PAUSED, Kwave::REC_UNINITIALIZED, and Kwave::RecordDialog::updateBufferState().

Referenced by setup().

1129 {
1130  m_state = state;
1131  switch (m_state) {
1133  case Kwave::REC_EMPTY:
1134  case Kwave::REC_PAUSED:
1135  case Kwave::REC_DONE:
1136  // reset buffer status
1137  if (m_writers) {
1138  m_writers->flush();
1139  delete m_writers;
1140  m_writers = Q_NULLPTR;
1141  }
1142  m_buffers_recorded = 0;
1143  m_dialog->updateBufferState(0, 0);
1144  break;
1145  default:
1146  ;
1147  }
1148 }
void updateBufferState(unsigned int count, unsigned int total)
Kwave::RecordState m_state
Definition: RecordPlugin.h:246
unsigned int m_buffers_recorded
Definition: RecordPlugin.h:273
Kwave::MultiTrackWriter * m_writers
Definition: RecordPlugin.h:267
virtual void flush()
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
Here is the call graph for this function:
Here is the caller graph for this function:

◆ updateBufferProgressBar()

void Kwave::RecordPlugin::updateBufferProgressBar ( )
private

update the buffer progress bar

Definition at line 1151 of file RecordPlugin.cpp.

References Kwave::RecordParams::buffer_count, m_buffers_recorded, m_dialog, m_state, m_thread, Kwave::RecordDialog::params(), Kwave::RecordThread::queuedBuffers(), Kwave::REC_DONE, Kwave::REC_EMPTY, Kwave::REC_PAUSED, Kwave::RecordThread::remainingBuffers(), and Kwave::RecordDialog::updateBufferState().

Referenced by processBuffer().

1152 {
1153  Q_ASSERT(m_dialog);
1154  Q_ASSERT(m_thread);
1155  if (!m_dialog || !m_thread) return;
1156 
1157  unsigned int buffers_total = m_dialog->params().buffer_count;
1158 
1159  // if we are still recording: update the progress bar
1161  (m_state != Kwave::REC_DONE))
1162  {
1163  // count up the number of recorded buffers
1165 
1166  if (m_buffers_recorded <= buffers_total) {
1167  // buffers are just in progress of getting filled
1169  } else {
1170  // we have remaining+1 buffers (one is currently filled)
1171  unsigned int remaining = m_thread->remainingBuffers() + 1;
1172  if (remaining > buffers_total) remaining = buffers_total;
1173  m_dialog->updateBufferState(remaining, buffers_total);
1174  }
1175  } else {
1176  // no longer recording: count the buffer downwards
1177  unsigned int queued = m_thread->queuedBuffers();
1178  if (!queued) buffers_total = 0;
1179  m_dialog->updateBufferState(queued, buffers_total);
1180  }
1181 }
Kwave::RecordThread * m_thread
Definition: RecordPlugin.h:255
void updateBufferState(unsigned int count, unsigned int total)
Kwave::RecordState m_state
Definition: RecordPlugin.h:246
unsigned int m_buffers_recorded
Definition: RecordPlugin.h:273
Kwave::RecordDialog * m_dialog
Definition: RecordPlugin.h:252
unsigned int queuedBuffers()
Kwave::RecordParams & params()
unsigned int buffer_count
Definition: RecordParams.h:108
unsigned int remainingBuffers()
Here is the call graph for this function:
Here is the caller graph for this function:

Friends And Related Function Documentation

◆ InhibitRecordGuard

friend class InhibitRecordGuard
friend

Definition at line 101 of file RecordPlugin.h.

Member Data Documentation

◆ m_buffers_recorded

unsigned int Kwave::RecordPlugin::m_buffers_recorded
private

number of recorded buffers since start or continue or the number of buffers in the queue if recording stopped

Definition at line 273 of file RecordPlugin.h.

Referenced by processBuffer(), resetRecording(), stateChanged(), and updateBufferProgressBar().

◆ m_controller

Kwave::RecordController Kwave::RecordPlugin::m_controller
private

controller for the recording engine

Definition at line 243 of file RecordPlugin.h.

Referenced by flushPrerecordingQueue(), processBuffer(), resetRecording(), setDevice(), setup(), and startRecording().

◆ m_decoder

Kwave::SampleDecoder* Kwave::RecordPlugin::m_decoder
private

decoder for converting raw data to samples

Definition at line 258 of file RecordPlugin.h.

Referenced by flushPrerecordingQueue(), processBuffer(), setup(), setupRecordThread(), startRecording(), and ~RecordPlugin().

◆ m_device

◆ m_device_name

QString Kwave::RecordPlugin::m_device_name
private

◆ m_dialog

◆ m_inhibit_count

unsigned int Kwave::RecordPlugin::m_inhibit_count
private

recursion level for inhibiting recording

Definition at line 276 of file RecordPlugin.h.

Referenced by enterInhibit(), and leaveInhibit().

◆ m_method

Kwave::record_method_t Kwave::RecordPlugin::m_method
private

last recording method

Definition at line 237 of file RecordPlugin.h.

Referenced by setDevice(), and setMethod().

◆ m_prerecording_queue

QVector<Kwave::SampleFIFO> Kwave::RecordPlugin::m_prerecording_queue
private

set of queues for buffering prerecording data, one for each track

Definition at line 264 of file RecordPlugin.h.

Referenced by enqueuePrerecording(), flushPrerecordingQueue(), processBuffer(), recordStopped(), setup(), and setupRecordThread().

◆ m_retry_timer

QTimer Kwave::RecordPlugin::m_retry_timer
private

timer for retrying "open"

Definition at line 282 of file RecordPlugin.h.

Referenced by closeDevice(), RecordPlugin(), and setDevice().

◆ m_state

Kwave::RecordState Kwave::RecordPlugin::m_state
private

global state of the plugin

Definition at line 246 of file RecordPlugin.h.

Referenced by processBuffer(), startRecording(), stateChanged(), and updateBufferProgressBar().

◆ m_thread

Kwave::RecordThread* Kwave::RecordPlugin::m_thread
private

◆ m_trigger_value

QVector<float> Kwave::RecordPlugin::m_trigger_value
private

buffer for trigger values

Definition at line 279 of file RecordPlugin.h.

Referenced by checkTrigger(), and setupRecordThread().

◆ m_writers

Kwave::MultiTrackWriter* Kwave::RecordPlugin::m_writers
private

The documentation for this class was generated from the following files: