qjackrcd-1.1.0~ds0.orig/0000775000175000017500000000000012663263214014726 5ustar alessioalessioqjackrcd-1.1.0~ds0.orig/record-red.png0000664000175000017500000000264312521001153017450 0ustar alessioalessioPNG  IHDR00WjIDATh՚MLSYcT ˤPM8@ ,fqafB 10hX9Ƹ\0FJ.#D"6iY>O}7={;yU`%J8 8.Hs۩|[ %`;[~2& kR6%<F{`X+cGڎ?(cR%*$0 ᬑ6|e7VsTezyxRN[n3b ځ$/EEm*! ds6e! ת~8 &W(>*agMUnE;:p8&dBj5PƢ5`<..^buؘz)TN'QnCCZg,{[[i jb2ID8H0.׶xfdӋx#Z\x_mi%|h_X !Dì]|) 7**7ÇuR@͛9eghqQܓSy0Ɏe׋BY}JD@ח. /ʝ]]"r|q +%w>:6ƂH`uZ^l\!<8kJ4 ظsG m68ԁ*hMFBM])FG^5Fw;;-ǶfgfͲ5;hjP*%`%~[^m'٦;4SF P$,dڈmƆ嘿˶,hjPbJ10 v40Pr++c|:iUYBؘDk;B:6&=PU5B:]jTJ,8'''q56khl$xRkn-f b ?UG睗/y33CmF)aSugPHl;LO4+W,k!O($cb4TJɜ=hKڑ L]HQ9]f i5ӺyQ|ee22#H8~%2G!4z&ó^^OLPuzrgoYo/z&S fY!zbMx /FFlAFb+JA^lӨ¬iOmpojk!\c.\ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************************************/ /** * @file recorder.cpp * $Author: orouits $ * $Date: 2015-05-02 00:42:24 +0200 (sam. 02 mai 2015) $ * $Revision: 94 $ * @brief Implementation of Recorder class */ #include #include #include #include #include #include #include "recorder.h" #include #include #include #include #include //============================================================================= // Internal defines //============================================================================= #define RCD_JK_INPUT_PORTNAME_1 "record_1" #define RCD_JK_INPUT_PORTNAME_2 "record_2" #define RCD_WAIT_TIMEOUT_MS 1000 #define RCD_SIG_CHANGE_COUNT 4 #define RCD_FRAME_SIZE sizeof(float) #define RCD_RINGBUFFER_FRAMES (64*1024) #define RCD_RINGBUFFER_SIZE (2*RCD_RINGBUFFER_FRAMES*RCD_FRAME_SIZE) #define RCD_BUFFER_FRAMES (2*1024) #define RCD_BUFFER_SIZE (2*RCD_BUFFER_FRAMES*RCD_FRAME_SIZE) //============================================================================= // Jack callback to object calls //============================================================================= int jack_process (jack_nframes_t nframes, void *recorder) { return ((Recorder*)recorder)->jackProcess(nframes); } int jack_sync (jack_transport_state_t state, jack_position_t *pos, void *recorder) { return ((Recorder*)recorder)->jackSync(state, pos); } void jack_portreg (jack_port_id_t port_id, int reg, void *recorder) { ((Recorder*)recorder)->jackPortReg(port_id, reg); } void jack_shutdown (void *recorder) { ((Recorder*)recorder)->jackShutdown(); } //============================================================================= // Recorder cont/dest methods //============================================================================= Recorder::Recorder(QString jackName) { this->jackName = jackName; sndFile = NULL; outputDir = QDir::home(); currentFilePath = ""; processFilePath = ""; processCmdLine = ""; overruns = 0; pauseActivationMax = 0; pauseActivationCount = pauseActivationMax + 1; jackTransMode = true; jackAutoMode = true; if ((jackClient = jack_client_open(jackName.toLatin1(), jack_options_t(JackNullOption | JackUseExactName), 0)) == 0) { throw "Can't start or connect to jack server"; } sampleRate = jack_get_sample_rate(jackClient); jackInputPort1 = jack_port_register (jackClient, RCD_JK_INPUT_PORTNAME_1, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); jackInputPort2 = jack_port_register (jackClient, RCD_JK_INPUT_PORTNAME_2, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); jack_set_process_callback(jackClient, jack_process, this); jack_set_sync_callback(jackClient, jack_sync, this); jack_on_shutdown (jackClient, jack_shutdown, this); jack_set_port_registration_callback(jackClient, jack_portreg, this); jackRingBuffer = jack_ringbuffer_create(RCD_RINGBUFFER_SIZE); jack_ringbuffer_reset(jackRingBuffer); currentBuffer = new float[RCD_BUFFER_FRAMES*2]; memset(currentBuffer, 0, RCD_BUFFER_SIZE); alternateBuffer = new float[RCD_BUFFER_FRAMES*2]; memset(alternateBuffer, 0, RCD_BUFFER_SIZE); setRecording(false); setShutdown(false); setSplitMode(false); setPauseActivationDelay(3); setPauseLevel(-20); // start the recorder thread start(); } Recorder::~Recorder() { setShutdown(true); // wait for recorder thread shutdown wait(RCD_WAIT_TIMEOUT_MS); // free / close objects if (currentBuffer) delete currentBuffer; if (alternateBuffer) delete alternateBuffer; if (jackRingBuffer) jack_ringbuffer_free(jackRingBuffer); if (jackClient) jack_client_close(jackClient); } //============================================================================= // Recorder jack methods //============================================================================= int Recorder::jackSync(jack_transport_state_t state, jack_position_t *pos) { if (isJackTransMode()) { if (state == JackTransportStopped) setRecording(false); else if (state == JackTransportStarting) setRecording(true); } return isRecordEnabled(); } int Recorder::jackProcess(jack_nframes_t nframes) { int rc = 0; jack_default_audio_sample_t *in1 =(jack_default_audio_sample_t *)jack_port_get_buffer (jackInputPort1, nframes); jack_default_audio_sample_t *in2 =(jack_default_audio_sample_t *)jack_port_get_buffer (jackInputPort2, nframes); // the ringbuffer will transmit data to reorder thread (non RT) size_t rbspace = jack_ringbuffer_write_space(jackRingBuffer); if (rbspace < (2*nframes*RCD_FRAME_SIZE)) { // the ringbuffer is full, IO thread is too late because of IO locks or overloading overruns++; rc = 1; } else { // tmp value to be shure of data convertion float value; // write interlived stereo data into the ringbuffer for(jack_nframes_t i = 0; i < nframes; i++) { value = in1[i]; jack_ringbuffer_write (jackRingBuffer, (const char *)(&value), RCD_FRAME_SIZE); value = in2[i]; jack_ringbuffer_write (jackRingBuffer, (const char *)(&value), RCD_FRAME_SIZE); } } // wakeup recorder thread because there is data to process if (dataReadyMutex.tryLock()) { dataReady.wakeAll(); dataReadyMutex.unlock(); } return rc; } void Recorder::jackPortReg(jack_port_id_t port_id, int reg) { if (isJackAutoMode() && reg) { // if a port is registerred, its ID is put in queue for processing by the recorder thread jackPortRegQueue.enqueue(port_id); } } void Recorder::jackShutdown() { setShutdown(true); } //============================================================================= // Recorder public methods //============================================================================= //============================================================================= // Recorder internal methods //============================================================================= // The recorder thread run function, all recording algorithm is managed from here void Recorder::run() { int loopCounter = 0; // start jack incomming sound jack_activate(jackClient); // this computed attribute must be initialized before entering the main loop computePauseActivationMax(); // to start always in pause mode if under pause level. pauseActivationCount = pauseActivationMax + 1; // initial signal for listeners emit statusChanged(); // the main loop (while shutdown state is off) while (!isShutdown()) { // check if therre is some things to do about registration ports (queue not empty) checkJackAutoConnect(); // while ringbuffer has data. while (jack_ringbuffer_read_space(jackRingBuffer) >= RCD_BUFFER_SIZE) { // switch alternate to current buffer and clean it switchBuffer(); // read the current buffer from ringbuffer readCurrentBuffer(); // comute levels (DB) computeCurrentBufferLevels(); // delay may have changed computePauseActivationMax(); if (isRecording()) { // a file must be open on theses status values if (!isFile()) newFile(); if (isPauseLevel()) { if (pauseActivationCount < pauseActivationMax) { // the activation delay is not reached, continue to write previous buffer writeAlternateBuffer(); pauseActivationCount++; } else if (pauseActivationCount == pauseActivationMax) { // the activation delay is reached, fadeout previous buffer to eliminate noises and write it. fadeoutAlternateBuffer(); writeAlternateBuffer(); if (splitMode) { // new file will close current file newFile(); } pauseActivationCount++; } } else { if (pauseActivationCount > pauseActivationMax) // we were in pause satuts, fadein previous buffer to eliminate noises and write it. fadeinAlternateBuffer(); writeAlternateBuffer(); pauseActivationCount = 0; } } else { closeFile(); // to re-start always in pause mode. pauseActivationCount = pauseActivationMax + 1; } // update disk space compute computeDiskSpace(); if (loopCounter >= RCD_SIG_CHANGE_COUNT) { // notify listeners emit statusChanged(); loopCounter = 0; } else loopCounter++; } // wait for new data dataReady.wait(&dataReadyMutex, RCD_WAIT_TIMEOUT_MS); } // to be shure that file is closed closeFile(); // stop jack incomming sound jack_deactivate(jackClient); dataReadyMutex.unlock(); } void Recorder::computePauseActivationMax() { pauseActivationMax = (sampleRate * pauseActivationDelay ) / RCD_BUFFER_FRAMES; } void Recorder::computeCurrentBufferLevels() { float sumsqr_l = 0; float sumsqr_r = 0; int ibuf = 0; for (int i = 0; i < RCD_BUFFER_FRAMES; i++) { sumsqr_l += currentBuffer[ibuf]*currentBuffer[ibuf]; ibuf++; sumsqr_r += currentBuffer[ibuf]*currentBuffer[ibuf]; ibuf++; } float rms_l = sqrtf( sumsqr_l / ((float)RCD_BUFFER_FRAMES) ); float rms_r = sqrtf( sumsqr_r / ((float)RCD_BUFFER_FRAMES) ); float db_l = log10f( rms_l ) * 10; float db_r = log10f( rms_r ) * 10; leftLevel = db_l < - 40 ? - 40 : db_l; rightLevel = db_r < - 40 ? - 40 : db_r; } bool Recorder::isRecordEnabled() { return QFileInfo(outputDir.absolutePath()).isWritable(); } void Recorder::computeDiskSpace() { QStorageInfo info(outputDir); if (info.isValid()) diskSpace = 100 - (info.bytesAvailable() * 100) / info.bytesTotal(); else diskSpace = -1; } void Recorder::computeFilePath() { currentFilePath = outputDir.absoluteFilePath( jackName.toLower() + "-" + QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss") + ".wav" ); } void Recorder::newFile() { // new file begins always by closing current if exists closeFile(); SF_INFO sfinfo; sfinfo.format = SF_FORMAT_WAV|SF_FORMAT_FLOAT; sfinfo.channels = 2; sfinfo.samplerate = sampleRate; sfinfo.frames = RCD_BUFFER_FRAMES; computeFilePath(); sndFile = sf_open (currentFilePath.toLocal8Bit().constData(), SFM_WRITE, &sfinfo); } void Recorder::closeFile() { // this method is safe if no file is open. if ( isFile() ) { sf_close (sndFile); sndFile = NULL; // closing file allways involve post processing to start. processFile(); } currentFilePath = ""; } void Recorder::switchBuffer() { // switch current and alternate buffer float* tmpBuffer = currentBuffer; currentBuffer = alternateBuffer; alternateBuffer = tmpBuffer; // clean buffer memset(currentBuffer, 0, RCD_BUFFER_SIZE); } void Recorder::readCurrentBuffer() { // read ringbuffer jack_ringbuffer_read(jackRingBuffer, (char*)(currentBuffer), RCD_BUFFER_SIZE); } void Recorder::writeAlternateBuffer() { sf_writef_float(sndFile, alternateBuffer, RCD_BUFFER_FRAMES); } void Recorder::fadeinAlternateBuffer() { float gain = 0; float gaininc = 1 / float(RCD_BUFFER_FRAMES); int ibuf = 0; for (int i = 0; i < RCD_BUFFER_FRAMES; i++) { alternateBuffer[ibuf++] *= gain; alternateBuffer[ibuf++] *= gain; gain += gaininc; } } void Recorder::fadeoutAlternateBuffer() { float gain = 1; float gaininc = 1 / float(RCD_BUFFER_FRAMES); int ibuf = 0; for (int i = 0; i < RCD_BUFFER_FRAMES; i++) { alternateBuffer[ibuf++] *= gain; alternateBuffer[ibuf++] *= gain; gain -= gaininc; } } void Recorder::processFile() { // only do post process if a command line is defined if (!processCmdLine.isEmpty() && !currentFilePath.isEmpty()) { QStringList args; args.append("-c"); args.append(processCmdLine); args.append(currentFilePath); QProcess pr; pr.startDetached("bash", args); processFilePath = currentFilePath; } } QString Recorder::getJackConnections(jack_port_t* jackPort) { const char** connections = NULL; QString result = ""; if ((connections = jack_port_get_all_connections (jackClient, jackPort)) != NULL) { for (int i = 0; connections[i]; i++) { result += QString(connections[i]) + ";"; //printf ("%s\n", connections[i]); } jack_free ((void*)connections); } return result; } void Recorder::setJackConnections(QString cnxLine, jack_port_t* jackPort) { QStringList strList = cnxLine.split(';', QString::SkipEmptyParts); for (int i = 0; i < strList.count() ; i++) { jack_connect(jackClient, strList.at(i).toLocal8Bit().constData(), jack_port_name(jackPort) ); } } void Recorder::checkJackAutoConnect() { while (!jackPortRegQueue.empty()) { jack_port_t* port = jack_port_by_id(jackClient, jackPortRegQueue.dequeue()); if (jack_port_flags(port) & JackPortIsOutput) { QString portName = jack_port_name(port); if (jack_port_connected(jackInputPort1) == 0) jack_connect(jackClient, portName.toLatin1().constData(), jack_port_name(jackInputPort1) ); else if (jack_port_connected(jackInputPort2) == 0) jack_connect(jackClient, portName.toLatin1().constData(), jack_port_name(jackInputPort2) ); } } } qjackrcd-1.1.0~ds0.orig/qjackrcd_de.qm0000664000175000017500000000261112521001153017500 0ustar alessioalessio This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************************************/ /** * @file main.cpp * $Author: orouits $ * $Date: 2015-04-25 15:25:44 +0200 (sam. 25 avril 2015) $ * $Revision: 85 $ * @brief Main function implementation */ /** * @mainpage * * QJackRcd is a simple QT application to record JACK server outputs (use it with QJackCtl) * * The initial goal of this project is to record from an old tape, with an automatic split/pause feature when you are away. Another goal is to have a litle tool ready to use with a minimum of configuration for simple stereo recording needs. * It manages natively silence by threshold and activation time. Silence event can be used to pause the record or to split files by closing the current record and opening a new one. * Optionaly QJackRcd is enable to post-process each file record at closure in background mode. the command is a simple bash command. * * Made with QTCreator * It Depends on jack, sndfile and qt4 libraries. */ #include "mainwindow.h" #include #include #include #define REC_JK_NAME "QJackRcd" ///< Name of the recorder instance used in jack client name /** * @fn int main (int argc, char *argv[]) * @brief Program entry. * * Main doesn't take any special paramerter, only standard QT parameters. * * @return 0 if normal GUI quit. */ int main(int argc, char *argv[]) { // The application and translator QApplication application(argc, argv); QString locale = QLocale::system().name(); QTranslator translator; // for packaged system install if (!translator.load(QString("qjackrcd_") + locale, "/usr/share/qjackrcd/locale")) // for install from source if (!translator.load(QString("qjackrcd_") + locale, "/usr/local/share/qjackrcd/locale")) // for dev test translator.load(QString("qjackrcd_") + locale, "locale"); application.installTranslator(&translator); // The recorder Recorder recorder(REC_JK_NAME); // The window MainWindow window(&recorder); // Go ! window.show(); return application.exec(); } qjackrcd-1.1.0~ds0.orig/qjrmeter.h0000664000175000017500000000605512521001153016717 0ustar alessioalessio/*************************************************************************** Copyright (C) 2011 - Olivier ROUITS This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************************************/ /** * @file qjrmeter.h * $Author: orouits $ * $Date: 2015-04-25 15:25:44 +0200 (sam. 25 avril 2015) $ * $Revision: 85 $ * @brief Header for QJRMeter class from Giuseppe Cigala code (qvumeter) */ #ifndef QJRMETER_H #define QJRMETER_H #include #include #define QJRM_MAXLEVEL 3 ///< Max DB showable level by the vumeter #define QJRM_MINLEVEL -40 ///< Min DB showable level by the vumeter /** * @class QJRMeter * @brief DB Meter widget for QJackRcd. */ class QJRMeter : public QWidget { Q_OBJECT Q_PROPERTY(QColor colorBack READ getColorBack WRITE setColorBack); Q_PROPERTY(QColor colorLevel READ getColorLevel WRITE setColorLevel); Q_PROPERTY(QColor colorLow READ getColorLow WRITE setColorLow); Q_PROPERTY(QColor colorHigh READ getColorHigh WRITE setColorHigh); Q_PROPERTY(double leftLevel READ getLeftLevel WRITE setLeftLevel); Q_PROPERTY(double rightLevel READ getRightLevel WRITE setRightLevel); Q_PROPERTY(double compLevel READ getCompLevel WRITE setCompLevel); QColor getColorBack() const { return colorBack; } QColor getColorLevel() const { return colorLevel; } QColor getColorLow() const { return colorLow; } QColor getColorHigh() const { return colorHigh; } double getLeftLevel() const { return leftLevel; } double getRightLevel() const { return rightLevel; } double getCompLevel() const { return compLevel; } public: QJRMeter(QWidget *parent = 0); QSize minimumSizeHint() const; QSize sizeHint() const; signals: void valueLChanged(double); void valueRChanged(double); public slots: void setColorBack(QColor); void setColorLevel(QColor); void setColorHigh(QColor); void setColorLow(QColor); void setLeftLevel(double); void setRightLevel(double); void setCompLevel(double); protected: void paintEvent(QPaintEvent *); void paintBorder(); void paintBar(); private: double leftLevel; double rightLevel; double compLevel; QColor colorBack; QColor colorLevel; QColor colorHigh; QColor colorLow; }; #endif qjackrcd-1.1.0~ds0.orig/LICENSE0000664000175000017500000000142412521001153015715 0ustar alessioalessioQJackRcd, a simple "turnkey" jack QT recorder. Copyright (C) 2011 - Olivier ROUITS This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. qjackrcd-1.1.0~ds0.orig/mainwindow.h0000664000175000017500000000434612521001153017243 0ustar alessioalessio/*************************************************************************** Copyright (C) 2011 - Olivier ROUITS This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ***************************************************************************/ /** * @file mainwindow.h * $Author: orouits $ * $Date: 2015-04-26 02:05:52 +0200 (dim. 26 avril 2015) $ * $Revision: 87 $ * @brief Header for MainWindow class */ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include "recorder.h" namespace Ui { class MainWindow; } /** * @class MainWindow * @brief Encapsulation of all the GUI of the application. */ class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(Recorder *recorder, QWidget *parent = 0); ~MainWindow(); void closeEvent(QCloseEvent *event); void readSettings(); void writeSettings(); private: Ui::MainWindow *ui; Recorder *recorder; QIcon *iconGreen; QIcon *iconRed; QIcon *iconOrange; private slots: void on_pauseLevelSpin_valueChanged(double value); void on_pauseDelaySpin_valueChanged(double value); void on_recButton_clicked(); void on_pauseSplitCheck_stateChanged(int value); void on_postActionCombo_currentIndexChanged(int index); void on_postCmdEdit_textChanged(const QString &text); void onRecorderStatusChanged(); void on_optJkAutoCheck_stateChanged(int value); void on_optJktransCheck_stateChanged(int value); void on_optOutputDirEdit_textChanged(const QString &text); void on_optOutputDirButton_clicked(); }; #endif // MAINWINDOW_H qjackrcd-1.1.0~ds0.orig/qjackrcd_cs.qm0000664000175000017500000000257112521001153017522 0ustar alessioalessioO}7={;yU`%J8 8.Hs۩|[ %`;[~2& kR6%<F{`X+cGڎ?(cR%*$0 ᬑ6|e7VsTezyxRN[n3b ځ$/EEm*! ds6e! ת~8 &W(>*agMUnE;:p8&dBj5PƢ5`<..^buؘz)TN'QnCCZg,{[[i jb2ID8H0.׶xfdӋx#Z\x_mi%|h_X !Dì]|) 7**7ÇuR@͛9eghqQܓSy0Ɏe׋BY}JD@ח. /ʝ]]"r|q +%w>:6ƂH`uZ^l\!<8kJ4 ظsG m68ԁ*hMFBM])FG^5Fw;;-ǶfgfͲ5;hjP*%`%~[^m'٦;4SF P$,dڈmƆ嘿˶,hjPbJ10 v40Pr++c|:iUYBؘDk;B:6&=PU5B:]jTJ,8'''q56khl$xRkn-f b ?UG睗/y33CmF)aSugPHl;LO4+W,k!O($cb4TJɜ=hKڑ L]HQ9]f i5ӺyQ|ee22#H8~%2G!4z&ó^^OLPuzrgoYo/z&S fY!zbMx /FFlAFb+JA^lӨ¬iOmpojk!\c.\