Improvements to Audio Recording
This commit is contained in:
parent
6f8de8cbf3
commit
34075514d2
2 changed files with 387 additions and 126 deletions
|
@ -66,29 +66,47 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
m_saveButton = new QPushButton(tr("Save and Insert"));
|
m_saveButton = new QPushButton(tr("Save and Insert"));
|
||||||
m_pauseRecordingButton = new QPushButton(this);
|
m_pauseRecordingButton = new QPushButton(this);
|
||||||
m_pausePlaybackButton = new QPushButton(this);
|
m_pausePlaybackButton = new QPushButton(this);
|
||||||
// m_refreshDevicesButton = new QPushButton(tr("Refresh"));
|
m_refreshDevicesButton = new QPushButton(this);
|
||||||
m_duration = new QLabel("00:00");
|
m_duration = new QLabel("00:00.000");
|
||||||
m_playDuration = new QLabel("00:00");
|
m_playDuration = new QLabel("00:00.000");
|
||||||
m_deviceListCB = new QComboBox();
|
m_deviceListCB = new QComboBox();
|
||||||
m_audioLevelsDisplay = new AudioLevelsDisplay(this);
|
m_audioLevelsDisplay = new AudioLevelsDisplay(this);
|
||||||
m_playXSheetCB = new QCheckBox(tr("Sync with Scene"), this);
|
m_playXSheetCB = new QCheckBox(tr("Sync with XSheet/Timeline"), this);
|
||||||
m_timer = new QElapsedTimer();
|
m_timer = new QElapsedTimer();
|
||||||
m_recordedLevels = QMap<qint64, double>();
|
m_recordedLevels = QMap<qint64, double>();
|
||||||
m_oldElapsed = 0;
|
m_oldElapsed = 0;
|
||||||
m_probe = new QAudioProbe;
|
|
||||||
m_player = new QMediaPlayer(this);
|
m_player = new QMediaPlayer(this);
|
||||||
m_console = FlipConsole::getCurrent();
|
m_console = FlipConsole::getCurrent();
|
||||||
m_audioRecorder = new QAudioRecorder;
|
|
||||||
|
|
||||||
m_recordButton->setMaximumWidth(25);
|
m_labelDevice = new QLabel(tr("Device: "));
|
||||||
m_playButton->setMaximumWidth(25);
|
m_labelSamplerate = new QLabel(tr("Sample rate: "));
|
||||||
m_pauseRecordingButton->setMaximumWidth(25);
|
m_labelSamplefmt = new QLabel(tr("Sample format: "));
|
||||||
m_pausePlaybackButton->setMaximumWidth(25);
|
m_comboSamplerate = new QComboBox();
|
||||||
|
m_comboSamplefmt = new QComboBox();
|
||||||
|
m_comboSamplerate->addItem(tr("8000 Hz"), QVariant::fromValue(8000));
|
||||||
|
m_comboSamplerate->addItem(tr("11025 Hz"), QVariant::fromValue(11025));
|
||||||
|
m_comboSamplerate->addItem(tr("22050 Hz"), QVariant::fromValue(22050));
|
||||||
|
m_comboSamplerate->addItem(tr("44100 Hz"), QVariant::fromValue(44100));
|
||||||
|
m_comboSamplerate->addItem(tr("48000 Hz"), QVariant::fromValue(48000));
|
||||||
|
m_comboSamplerate->addItem(tr("96000 Hz"), QVariant::fromValue(96000));
|
||||||
|
m_comboSamplerate->setCurrentIndex(3); // 44.1KHz
|
||||||
|
m_comboSamplefmt->addItem(tr("Mono 8-Bits"), QVariant::fromValue(9));
|
||||||
|
m_comboSamplefmt->addItem(tr("Stereo 8-Bits"), QVariant::fromValue(10));
|
||||||
|
m_comboSamplefmt->addItem(tr("Mono 16-Bits"), QVariant::fromValue(17));
|
||||||
|
m_comboSamplefmt->addItem(tr("Stereo 16-Bits"), QVariant::fromValue(18));
|
||||||
|
m_comboSamplefmt->setCurrentIndex(2); // Mono 16-Bits
|
||||||
|
|
||||||
|
m_recordButton->setMaximumWidth(32);
|
||||||
|
m_playButton->setMaximumWidth(32);
|
||||||
|
m_pauseRecordingButton->setMaximumWidth(32);
|
||||||
|
m_pausePlaybackButton->setMaximumWidth(32);
|
||||||
|
m_refreshDevicesButton->setMaximumWidth(25);
|
||||||
|
|
||||||
QString playDisabled = QString(":Resources/play_disabled.svg");
|
QString playDisabled = QString(":Resources/play_disabled.svg");
|
||||||
QString pauseDisabled = QString(":Resources/pause_disabled.svg");
|
QString pauseDisabled = QString(":Resources/pause_disabled.svg");
|
||||||
QString stopDisabled = QString(":Resources/stop_disabled.svg");
|
QString stopDisabled = QString(":Resources/stop_disabled.svg");
|
||||||
QString recordDisabled = QString(":Resources/record_disabled.svg");
|
QString recordDisabled = QString(":Resources/record_disabled.svg");
|
||||||
|
QString refreshDisabled = QString(":Resources/repeat_icon.svg");
|
||||||
|
|
||||||
m_pauseIcon = createQIcon("pause");
|
m_pauseIcon = createQIcon("pause");
|
||||||
m_pauseIcon.addFile(pauseDisabled, QSize(), QIcon::Disabled);
|
m_pauseIcon.addFile(pauseDisabled, QSize(), QIcon::Disabled);
|
||||||
|
@ -98,6 +116,9 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
m_recordIcon.addFile(recordDisabled, QSize(), QIcon::Disabled);
|
m_recordIcon.addFile(recordDisabled, QSize(), QIcon::Disabled);
|
||||||
m_stopIcon = createQIcon("stop");
|
m_stopIcon = createQIcon("stop");
|
||||||
m_stopIcon.addFile(stopDisabled, QSize(), QIcon::Disabled);
|
m_stopIcon.addFile(stopDisabled, QSize(), QIcon::Disabled);
|
||||||
|
m_refreshIcon = createQIcon("repeat");
|
||||||
|
m_refreshIcon.addFile(refreshDisabled, QSize(), QIcon::Disabled);
|
||||||
|
|
||||||
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
||||||
m_pauseRecordingButton->setIconSize(QSize(17, 17));
|
m_pauseRecordingButton->setIconSize(QSize(17, 17));
|
||||||
m_playButton->setIcon(m_playIcon);
|
m_playButton->setIcon(m_playIcon);
|
||||||
|
@ -106,12 +127,32 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
m_recordButton->setIconSize(QSize(17, 17));
|
m_recordButton->setIconSize(QSize(17, 17));
|
||||||
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
||||||
m_pausePlaybackButton->setIconSize(QSize(17, 17));
|
m_pausePlaybackButton->setIconSize(QSize(17, 17));
|
||||||
|
m_refreshDevicesButton->setIcon(m_refreshIcon);
|
||||||
|
m_refreshDevicesButton->setIconSize(QSize(17, 17));
|
||||||
|
|
||||||
QStringList inputs = m_audioRecorder->audioInputs();
|
// Enumerate devices and initialize default device
|
||||||
m_deviceListCB->addItems(inputs);
|
enumerateAudioDevices("");
|
||||||
QString selectedInput = m_audioRecorder->defaultAudioInput();
|
QAudioDeviceInfo m_audioDeviceInfo = QAudioDeviceInfo::defaultInputDevice();
|
||||||
m_deviceListCB->setCurrentText(selectedInput);
|
QAudioFormat format;
|
||||||
m_audioRecorder->setAudioInput(selectedInput);
|
format.setSampleRate(44100);
|
||||||
|
format.setChannelCount(1);
|
||||||
|
format.setSampleSize(16);
|
||||||
|
format.setSampleType(QAudioFormat::SignedInt);
|
||||||
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
format.setCodec("audio/pcm");
|
||||||
|
if (!m_audioDeviceInfo.isFormatSupported(format)) {
|
||||||
|
format = m_audioDeviceInfo.nearestFormat(format);
|
||||||
|
}
|
||||||
|
m_audioInput = new QAudioInput(m_audioDeviceInfo, format);
|
||||||
|
m_audioWriterWAV = new AudioWriterWAV(format);
|
||||||
|
|
||||||
|
// Tool tips to provide additional info to the user
|
||||||
|
m_deviceListCB->setToolTip(tr("Audio input device to record"));
|
||||||
|
m_comboSamplerate->setToolTip(tr("Number of samples per second, 44.1KHz = CD Quality"));
|
||||||
|
m_comboSamplefmt->setToolTip(tr("Number of channels and bits per sample, 16-bits recommended"));
|
||||||
|
m_playXSheetCB->setToolTip(tr("Play animation from current frame while recording/playback"));
|
||||||
|
m_saveButton->setToolTip(tr("Save recording and insert into new column"));
|
||||||
|
m_refreshDevicesButton->setToolTip(tr("Refresh list of connected audio input devices"));
|
||||||
|
|
||||||
m_topLayout->setMargin(5);
|
m_topLayout->setMargin(5);
|
||||||
m_topLayout->setSpacing(8);
|
m_topLayout->setSpacing(8);
|
||||||
|
@ -124,11 +165,19 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
recordGridLay->setHorizontalSpacing(2);
|
recordGridLay->setHorizontalSpacing(2);
|
||||||
recordGridLay->setVerticalSpacing(3);
|
recordGridLay->setVerticalSpacing(3);
|
||||||
{
|
{
|
||||||
recordGridLay->addWidget(m_deviceListCB, 0, 0, 1, 4, Qt::AlignCenter);
|
recordGridLay->addWidget(m_labelDevice, 0, 0, 1, 2, Qt::AlignRight);
|
||||||
// recordGridLay->addWidget(m_refreshDevicesButton, 0, 3, Qt::AlignLeft);
|
recordGridLay->addWidget(m_deviceListCB, 0, 2, 1, 2, Qt::AlignLeft);
|
||||||
recordGridLay->addWidget(new QLabel(tr(" ")), 1, 0, Qt::AlignCenter);
|
|
||||||
recordGridLay->addWidget(m_audioLevelsDisplay, 2, 0, 1, 4,
|
recordGridLay->addWidget(m_labelSamplerate, 1, 0, 1, 2, Qt::AlignRight);
|
||||||
|
recordGridLay->addWidget(m_comboSamplerate, 1, 2, 1, 1, Qt::AlignLeft);
|
||||||
|
recordGridLay->addWidget(m_refreshDevicesButton, 1, 3, Qt::AlignRight);
|
||||||
|
|
||||||
|
recordGridLay->addWidget(m_labelSamplefmt, 2, 0, 1, 2, Qt::AlignRight);
|
||||||
|
recordGridLay->addWidget(m_comboSamplefmt, 2, 2, 1, 2, Qt::AlignLeft);
|
||||||
|
|
||||||
|
recordGridLay->addWidget(m_audioLevelsDisplay, 3, 0, 1, 4,
|
||||||
Qt::AlignCenter);
|
Qt::AlignCenter);
|
||||||
|
recordGridLay->addWidget(m_playXSheetCB, 4, 0, 1, 5, Qt::AlignCenter);
|
||||||
QHBoxLayout *recordLay = new QHBoxLayout();
|
QHBoxLayout *recordLay = new QHBoxLayout();
|
||||||
recordLay->setSpacing(4);
|
recordLay->setSpacing(4);
|
||||||
recordLay->setContentsMargins(0, 0, 0, 0);
|
recordLay->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@ -139,7 +188,7 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
recordLay->addWidget(m_duration);
|
recordLay->addWidget(m_duration);
|
||||||
recordLay->addStretch();
|
recordLay->addStretch();
|
||||||
}
|
}
|
||||||
recordGridLay->addLayout(recordLay, 3, 0, 1, 4, Qt::AlignCenter);
|
recordGridLay->addLayout(recordLay, 5, 0, 1, 4, Qt::AlignCenter);
|
||||||
QHBoxLayout *playLay = new QHBoxLayout();
|
QHBoxLayout *playLay = new QHBoxLayout();
|
||||||
playLay->setSpacing(4);
|
playLay->setSpacing(4);
|
||||||
playLay->setContentsMargins(0, 0, 0, 0);
|
playLay->setContentsMargins(0, 0, 0, 0);
|
||||||
|
@ -150,11 +199,9 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
playLay->addWidget(m_playDuration);
|
playLay->addWidget(m_playDuration);
|
||||||
playLay->addStretch();
|
playLay->addStretch();
|
||||||
}
|
}
|
||||||
recordGridLay->addLayout(playLay, 4, 0, 1, 4, Qt::AlignCenter);
|
recordGridLay->addLayout(playLay, 6, 0, 1, 4, Qt::AlignCenter);
|
||||||
recordGridLay->addWidget(new QLabel(tr(" ")), 5, 0, Qt::AlignCenter);
|
recordGridLay->addWidget(new QLabel(tr(" ")), 7, 0, Qt::AlignCenter);
|
||||||
recordGridLay->addWidget(m_saveButton, 6, 0, 1, 4,
|
recordGridLay->addWidget(m_saveButton, 8, 0, 1, 4,
|
||||||
Qt::AlignCenter | Qt::AlignVCenter);
|
|
||||||
recordGridLay->addWidget(m_playXSheetCB, 7, 0, 1, 4,
|
|
||||||
Qt::AlignCenter | Qt::AlignVCenter);
|
Qt::AlignCenter | Qt::AlignVCenter);
|
||||||
}
|
}
|
||||||
recordGridLay->setColumnStretch(0, 0);
|
recordGridLay->setColumnStretch(0, 0);
|
||||||
|
@ -172,23 +219,6 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
|
|
||||||
m_playXSheetCB->setChecked(true);
|
m_playXSheetCB->setChecked(true);
|
||||||
|
|
||||||
m_probe->setSource(m_audioRecorder);
|
|
||||||
QAudioEncoderSettings audioSettings;
|
|
||||||
audioSettings.setCodec("audio/PCM");
|
|
||||||
// setting the sample rate to some value (like 44100)
|
|
||||||
// may cause divide-by-zero crash in QAudioDeviceInfo::nearestFormat()
|
|
||||||
// so here we set the value to -1, as the documentation says;
|
|
||||||
// "A value of -1 indicates the encoder should make an optimal choice"
|
|
||||||
audioSettings.setSampleRate(-1);
|
|
||||||
audioSettings.setChannelCount(1);
|
|
||||||
audioSettings.setBitRate(16);
|
|
||||||
audioSettings.setEncodingMode(QMultimedia::ConstantBitRateEncoding);
|
|
||||||
audioSettings.setQuality(QMultimedia::HighQuality);
|
|
||||||
m_audioRecorder->setContainerFormat("wav");
|
|
||||||
m_audioRecorder->setEncodingSettings(audioSettings);
|
|
||||||
|
|
||||||
connect(m_probe, SIGNAL(audioBufferProbed(QAudioBuffer)), this,
|
|
||||||
SLOT(processBuffer(QAudioBuffer)));
|
|
||||||
connect(m_playXSheetCB, SIGNAL(stateChanged(int)), this,
|
connect(m_playXSheetCB, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(onPlayXSheetCBChanged(int)));
|
SLOT(onPlayXSheetCBChanged(int)));
|
||||||
connect(m_saveButton, SIGNAL(clicked()), this, SLOT(onSaveButtonPressed()));
|
connect(m_saveButton, SIGNAL(clicked()), this, SLOT(onSaveButtonPressed()));
|
||||||
|
@ -199,16 +229,18 @@ AudioRecordingPopup::AudioRecordingPopup()
|
||||||
SLOT(onPauseRecordingButtonPressed()));
|
SLOT(onPauseRecordingButtonPressed()));
|
||||||
connect(m_pausePlaybackButton, SIGNAL(clicked()), this,
|
connect(m_pausePlaybackButton, SIGNAL(clicked()), this,
|
||||||
SLOT(onPausePlaybackButtonPressed()));
|
SLOT(onPausePlaybackButtonPressed()));
|
||||||
connect(m_audioRecorder, SIGNAL(durationChanged(qint64)), this,
|
connect(m_audioWriterWAV, SIGNAL(update(qint64)), this,
|
||||||
SLOT(updateRecordDuration(qint64)));
|
SLOT(updateRecordDuration(qint64)));
|
||||||
connect(m_console, SIGNAL(playStateChanged(bool)), this,
|
if (m_console) connect(m_console, SIGNAL(playStateChanged(bool)), this,
|
||||||
SLOT(onPlayStateChanged(bool)));
|
SLOT(onPlayStateChanged(bool)));
|
||||||
connect(m_deviceListCB, SIGNAL(currentTextChanged(const QString)), this,
|
connect(m_deviceListCB, SIGNAL(currentTextChanged(const QString)), this,
|
||||||
SLOT(onInputDeviceChanged()));
|
SLOT(onInputDeviceChanged()));
|
||||||
// connect(m_refreshDevicesButton, SIGNAL(clicked()), this,
|
connect(m_refreshDevicesButton, SIGNAL(clicked()), this,
|
||||||
// SLOT(onRefreshButtonPressed()));
|
SLOT(onRefreshButtonPressed()));
|
||||||
// connect(m_audioRecorder, SIGNAL(availableAudioInputsChanged()), this,
|
connect(m_comboSamplerate, SIGNAL(currentTextChanged(const QString)), this,
|
||||||
// SLOT(onRefreshButtonPressed()));
|
SLOT(onAudioSettingChanged()));
|
||||||
|
connect(m_comboSamplefmt, SIGNAL(currentTextChanged(const QString)), this,
|
||||||
|
SLOT(onAudioSettingChanged()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -218,11 +250,24 @@ AudioRecordingPopup::~AudioRecordingPopup() {}
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::onRecordButtonPressed() {
|
void AudioRecordingPopup::onRecordButtonPressed() {
|
||||||
if (m_audioRecorder->state() == QAudioRecorder::StoppedState) {
|
#if QT_VERSION >= 0x051000
|
||||||
if (m_audioRecorder->status() == QMediaRecorder::UnavailableStatus) {
|
if (m_audioInput->state() == QAudio::InterruptedState) {
|
||||||
|
DVGui::warning(
|
||||||
|
tr("The microphone is not available: "
|
||||||
|
"\nPlease select a different device or check the microphone."));
|
||||||
|
return;
|
||||||
|
} else if (m_audioInput->state() == QAudio::StoppedState) {
|
||||||
|
if (!m_console) {
|
||||||
|
DVGui::warning(
|
||||||
|
tr("Record failed: "
|
||||||
|
"\nMake sure there's XSheet or Timeline in the room."));
|
||||||
|
#else
|
||||||
|
if (m_audioInput->state() == QAudio::StoppedState) {
|
||||||
|
if (!m_console) {
|
||||||
DVGui::warning(
|
DVGui::warning(
|
||||||
tr("The microphone is not available: "
|
tr("The microphone is not available: "
|
||||||
"\nPlease select a different device or check the microphone."));
|
"\nPlease select a different device or check the microphone."));
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// clear the player in case the file is open there
|
// clear the player in case the file is open there
|
||||||
|
@ -236,8 +281,6 @@ void AudioRecordingPopup::onRecordButtonPressed() {
|
||||||
// (rarely)
|
// (rarely)
|
||||||
// could cause a crash. I think OT tried to import the level before the
|
// could cause a crash. I think OT tried to import the level before the
|
||||||
// final file was fully copied to the new location
|
// final file was fully copied to the new location
|
||||||
m_audioRecorder->setOutputLocation(
|
|
||||||
QUrl::fromLocalFile(m_filePath.getQString()));
|
|
||||||
if (TSystem::doesExistFileOrLevel(m_filePath)) {
|
if (TSystem::doesExistFileOrLevel(m_filePath)) {
|
||||||
TSystem::removeFileOrLevel(m_filePath);
|
TSystem::removeFileOrLevel(m_filePath);
|
||||||
}
|
}
|
||||||
|
@ -246,15 +289,21 @@ void AudioRecordingPopup::onRecordButtonPressed() {
|
||||||
m_playButton->setDisabled(true);
|
m_playButton->setDisabled(true);
|
||||||
m_pausePlaybackButton->setDisabled(true);
|
m_pausePlaybackButton->setDisabled(true);
|
||||||
m_pauseRecordingButton->setEnabled(true);
|
m_pauseRecordingButton->setEnabled(true);
|
||||||
|
m_deviceListCB->setDisabled(true);
|
||||||
|
m_refreshDevicesButton->setDisabled(true);
|
||||||
|
m_comboSamplerate->setDisabled(true);
|
||||||
|
m_comboSamplefmt->setDisabled(true);
|
||||||
m_recordedLevels.clear();
|
m_recordedLevels.clear();
|
||||||
m_oldElapsed = 0;
|
m_oldElapsed = 0;
|
||||||
m_pausedTime = 0;
|
m_pausedTime = 0;
|
||||||
m_startPause = 0;
|
m_startPause = 0;
|
||||||
m_endPause = 0;
|
m_endPause = 0;
|
||||||
m_stoppedAtEnd = false;
|
m_stoppedAtEnd = false;
|
||||||
m_playDuration->setText("00:00");
|
m_playDuration->setText("00:00.000");
|
||||||
m_timer->restart();
|
m_timer->restart();
|
||||||
m_audioRecorder->record();
|
m_audioWriterWAV->restart(m_audioInput->format());
|
||||||
|
m_audioWriterWAV->start();
|
||||||
|
m_audioInput->start(m_audioWriterWAV);
|
||||||
// this sometimes sets to one frame off, so + 1.
|
// this sometimes sets to one frame off, so + 1.
|
||||||
m_currentFrame = TApp::instance()->getCurrentFrame()->getFrame() + 1;
|
m_currentFrame = TApp::instance()->getCurrentFrame()->getFrame() + 1;
|
||||||
if (m_syncPlayback && !m_isPlaying) {
|
if (m_syncPlayback && !m_isPlaying) {
|
||||||
|
@ -264,13 +313,20 @@ void AudioRecordingPopup::onRecordButtonPressed() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
m_audioRecorder->stop();
|
m_audioInput->stop();
|
||||||
m_audioLevelsDisplay->setLevel(0);
|
m_audioWriterWAV->stop();
|
||||||
|
if (m_audioWriterWAV->save(m_filePath.getQString())) {
|
||||||
|
m_saveButton->setEnabled(true);
|
||||||
|
m_playButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
m_audioLevelsDisplay->setLevel(-1);
|
||||||
m_recordButton->setIcon(m_recordIcon);
|
m_recordButton->setIcon(m_recordIcon);
|
||||||
m_saveButton->setEnabled(true);
|
|
||||||
m_playButton->setEnabled(true);
|
|
||||||
m_pauseRecordingButton->setDisabled(true);
|
m_pauseRecordingButton->setDisabled(true);
|
||||||
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
||||||
|
m_deviceListCB->setEnabled(true);
|
||||||
|
m_refreshDevicesButton->setEnabled(true);
|
||||||
|
m_comboSamplerate->setEnabled(true);
|
||||||
|
m_comboSamplefmt->setEnabled(true);
|
||||||
if (m_syncPlayback) {
|
if (m_syncPlayback) {
|
||||||
if (m_isPlaying) {
|
if (m_isPlaying) {
|
||||||
m_console->pressButton(FlipConsole::ePause);
|
m_console->pressButton(FlipConsole::ePause);
|
||||||
|
@ -285,15 +341,18 @@ void AudioRecordingPopup::onRecordButtonPressed() {
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::updateRecordDuration(qint64 duration) {
|
void AudioRecordingPopup::updateRecordDuration(qint64 duration) {
|
||||||
// this is only called every second or so - sometimes duration ~= 950
|
|
||||||
// this gives some padding so it doesn't take two seconds to show one second
|
|
||||||
// has passed
|
|
||||||
if (duration % 1000 > 850) duration += 150;
|
|
||||||
int minutes = duration / 60000;
|
int minutes = duration / 60000;
|
||||||
int seconds = (duration / 1000) % 60;
|
int seconds = (duration / 1000) % 60;
|
||||||
|
int milis = duration % 1000;
|
||||||
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
|
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
|
||||||
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
|
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
|
||||||
m_duration->setText(strMinutes + ":" + strSeconds);
|
QString strMilis = QString::number(milis).rightJustified(3, '0');
|
||||||
|
m_duration->setText(strMinutes + ":" + strSeconds + "." + strMilis);
|
||||||
|
|
||||||
|
// Show and record amplitude
|
||||||
|
qreal level = m_audioWriterWAV->level();
|
||||||
|
m_audioLevelsDisplay->setLevel(level);
|
||||||
|
m_recordedLevels[duration / 20] = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -301,9 +360,11 @@ void AudioRecordingPopup::updateRecordDuration(qint64 duration) {
|
||||||
void AudioRecordingPopup::updatePlaybackDuration(qint64 duration) {
|
void AudioRecordingPopup::updatePlaybackDuration(qint64 duration) {
|
||||||
int minutes = duration / 60000;
|
int minutes = duration / 60000;
|
||||||
int seconds = (duration / 1000) % 60;
|
int seconds = (duration / 1000) % 60;
|
||||||
|
int milis = duration % 1000;
|
||||||
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
|
QString strMinutes = QString::number(minutes).rightJustified(2, '0');
|
||||||
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
|
QString strSeconds = QString::number(seconds).rightJustified(2, '0');
|
||||||
m_playDuration->setText(strMinutes + ":" + strSeconds);
|
QString strMilis = QString::number(milis).rightJustified(3, '0');
|
||||||
|
m_playDuration->setText(strMinutes + ":" + strSeconds + "." + strMilis);
|
||||||
|
|
||||||
// the qmediaplayer probe doesn't work on all platforms, so we fake it by
|
// the qmediaplayer probe doesn't work on all platforms, so we fake it by
|
||||||
// using
|
// using
|
||||||
|
@ -328,6 +389,10 @@ void AudioRecordingPopup::onPlayButtonPressed() {
|
||||||
m_recordButton->setDisabled(true);
|
m_recordButton->setDisabled(true);
|
||||||
m_saveButton->setDisabled(true);
|
m_saveButton->setDisabled(true);
|
||||||
m_pausePlaybackButton->setEnabled(true);
|
m_pausePlaybackButton->setEnabled(true);
|
||||||
|
m_deviceListCB->setDisabled(true);
|
||||||
|
m_refreshDevicesButton->setDisabled(true);
|
||||||
|
m_comboSamplerate->setDisabled(true);
|
||||||
|
m_comboSamplefmt->setDisabled(true);
|
||||||
m_stoppedAtEnd = false;
|
m_stoppedAtEnd = false;
|
||||||
m_player->play();
|
m_player->play();
|
||||||
// this sometimes sets to one frame off, so + 1.
|
// this sometimes sets to one frame off, so + 1.
|
||||||
|
@ -343,25 +408,29 @@ void AudioRecordingPopup::onPlayButtonPressed() {
|
||||||
m_playButton->setIcon(m_playIcon);
|
m_playButton->setIcon(m_playIcon);
|
||||||
m_pausePlaybackButton->setDisabled(true);
|
m_pausePlaybackButton->setDisabled(true);
|
||||||
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
||||||
|
m_deviceListCB->setEnabled(true);
|
||||||
|
m_refreshDevicesButton->setEnabled(true);
|
||||||
|
m_comboSamplerate->setEnabled(true);
|
||||||
|
m_comboSamplefmt->setEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::onPauseRecordingButtonPressed() {
|
void AudioRecordingPopup::onPauseRecordingButtonPressed() {
|
||||||
if (m_audioRecorder->state() == QAudioRecorder::StoppedState) {
|
if (m_audioInput->state() == QAudio::StoppedState) {
|
||||||
return;
|
return;
|
||||||
} else if (m_audioRecorder->state() == QAudioRecorder::PausedState) {
|
} else if (m_audioInput->state() == QAudio::SuspendedState) {
|
||||||
m_endPause = m_timer->elapsed();
|
m_endPause = m_timer->elapsed();
|
||||||
m_pausedTime += m_endPause - m_startPause;
|
m_pausedTime += m_endPause - m_startPause;
|
||||||
m_audioRecorder->record();
|
m_audioInput->resume();
|
||||||
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
||||||
if (m_syncPlayback && !m_isPlaying && !m_stoppedAtEnd) {
|
if (m_syncPlayback && !m_isPlaying && !m_stoppedAtEnd) {
|
||||||
m_console->pressButton(FlipConsole::ePlay);
|
m_console->pressButton(FlipConsole::ePlay);
|
||||||
m_isPlaying = true;
|
m_isPlaying = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_audioRecorder->pause();
|
m_audioInput->suspend();
|
||||||
m_pauseRecordingButton->setIcon(m_recordIcon);
|
m_pauseRecordingButton->setIcon(m_recordIcon);
|
||||||
m_startPause = m_timer->elapsed();
|
m_startPause = m_timer->elapsed();
|
||||||
if (m_syncPlayback && m_isPlaying) {
|
if (m_syncPlayback && m_isPlaying) {
|
||||||
|
@ -398,7 +467,7 @@ void AudioRecordingPopup::onPausePlaybackButtonPressed() {
|
||||||
void AudioRecordingPopup::onMediaStateChanged(QMediaPlayer::State state) {
|
void AudioRecordingPopup::onMediaStateChanged(QMediaPlayer::State state) {
|
||||||
// stopping can happen through the stop button or the file ending
|
// stopping can happen through the stop button or the file ending
|
||||||
if (state == QMediaPlayer::StoppedState) {
|
if (state == QMediaPlayer::StoppedState) {
|
||||||
m_audioLevelsDisplay->setLevel(0);
|
m_audioLevelsDisplay->setLevel(-1);
|
||||||
if (m_syncPlayback) {
|
if (m_syncPlayback) {
|
||||||
if (m_isPlaying) {
|
if (m_isPlaying) {
|
||||||
m_console->pressButton(FlipConsole::ePause);
|
m_console->pressButton(FlipConsole::ePause);
|
||||||
|
@ -410,6 +479,10 @@ void AudioRecordingPopup::onMediaStateChanged(QMediaPlayer::State state) {
|
||||||
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
m_pausePlaybackButton->setIcon(m_pauseIcon);
|
||||||
m_pausePlaybackButton->setDisabled(true);
|
m_pausePlaybackButton->setDisabled(true);
|
||||||
m_recordButton->setEnabled(true);
|
m_recordButton->setEnabled(true);
|
||||||
|
m_deviceListCB->setEnabled(true);
|
||||||
|
m_refreshDevicesButton->setEnabled(true);
|
||||||
|
m_comboSamplerate->setEnabled(true);
|
||||||
|
m_comboSamplefmt->setEnabled(true);
|
||||||
m_saveButton->setEnabled(true);
|
m_saveButton->setEnabled(true);
|
||||||
m_isPlaying = false;
|
m_isPlaying = false;
|
||||||
}
|
}
|
||||||
|
@ -426,36 +499,36 @@ void AudioRecordingPopup::onPlayXSheetCBChanged(int status) {
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Refresh isn't working right now, but I'm leaving the code in case a future
|
void AudioRecordingPopup::onRefreshButtonPressed() {
|
||||||
// change
|
QAudioDeviceInfo m_audioDeviceInfo =
|
||||||
// makes it work
|
m_deviceListCB->itemData(m_deviceListCB->currentIndex())
|
||||||
|
.value<QAudioDeviceInfo>();
|
||||||
|
|
||||||
// void AudioRecordingPopup::onRefreshButtonPressed() {
|
enumerateAudioDevices(m_audioDeviceInfo.deviceName());
|
||||||
// m_deviceListCB->clear();
|
}
|
||||||
// QStringList inputs = m_audioRecorder->audioInputs();
|
|
||||||
// int count = inputs.count();
|
|
||||||
// m_deviceListCB->addItems(inputs);
|
|
||||||
// QString selectedInput = m_audioRecorder->defaultAudioInput();
|
|
||||||
// m_deviceListCB->setCurrentText(selectedInput);
|
|
||||||
//
|
|
||||||
//}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::onInputDeviceChanged() {
|
void AudioRecordingPopup::onInputDeviceChanged() {
|
||||||
m_audioRecorder->setAudioInput(m_deviceListCB->currentText());
|
reinitAudioInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AudioRecordingPopup::onAudioSettingChanged() {
|
||||||
|
reinitAudioInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::onSaveButtonPressed() {
|
void AudioRecordingPopup::onSaveButtonPressed() {
|
||||||
if (m_audioRecorder->state() != QAudioRecorder::StoppedState) {
|
if (m_audioInput->state() != QAudio::StoppedState) {
|
||||||
m_audioRecorder->stop();
|
m_audioInput->stop();
|
||||||
m_audioLevelsDisplay->setLevel(0);
|
m_audioLevelsDisplay->setLevel(-1);
|
||||||
}
|
}
|
||||||
if (m_player->state() != QMediaPlayer::StoppedState) {
|
if (m_player->state() != QMediaPlayer::StoppedState) {
|
||||||
m_player->stop();
|
m_player->stop();
|
||||||
m_audioLevelsDisplay->setLevel(0);
|
m_audioLevelsDisplay->setLevel(-1);
|
||||||
}
|
}
|
||||||
if (!TSystem::doesExistFileOrLevel(m_filePath)) return;
|
if (!TSystem::doesExistFileOrLevel(m_filePath)) return;
|
||||||
|
|
||||||
|
@ -499,31 +572,6 @@ void AudioRecordingPopup::makePaths() {
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::processBuffer(const QAudioBuffer &buffer) {
|
|
||||||
// keep from processing too many times
|
|
||||||
// get 50 signals per second
|
|
||||||
if (m_timer->elapsed() < m_oldElapsed + 20) return;
|
|
||||||
m_oldElapsed = m_timer->elapsed() - m_pausedTime;
|
|
||||||
qint16 value = 0;
|
|
||||||
|
|
||||||
if (!buffer.format().isValid() ||
|
|
||||||
buffer.format().byteOrder() != QAudioFormat::LittleEndian)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (buffer.format().codec() != "audio/pcm") return;
|
|
||||||
|
|
||||||
const qint16 *data = buffer.constData<qint16>();
|
|
||||||
qreal maxValue = 0;
|
|
||||||
qreal tempValue = 0;
|
|
||||||
for (int i = 0; i < buffer.frameCount(); ++i) {
|
|
||||||
tempValue = qAbs(qreal(data[i]));
|
|
||||||
if (tempValue > maxValue) maxValue = tempValue;
|
|
||||||
}
|
|
||||||
maxValue /= SHRT_MAX;
|
|
||||||
m_audioLevelsDisplay->setLevel(maxValue);
|
|
||||||
m_recordedLevels[m_oldElapsed / 20] = maxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioRecordingPopup::onPlayStateChanged(bool playing) {
|
void AudioRecordingPopup::onPlayStateChanged(bool playing) {
|
||||||
// m_isPlaying = playing;
|
// m_isPlaying = playing;
|
||||||
if (!playing && m_isPlaying) m_stoppedAtEnd = true;
|
if (!playing && m_isPlaying) m_stoppedAtEnd = true;
|
||||||
|
@ -545,22 +593,33 @@ void AudioRecordingPopup::resetEverything() {
|
||||||
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
m_pauseRecordingButton->setIcon(m_pauseIcon);
|
||||||
m_pauseRecordingButton->setDisabled(true);
|
m_pauseRecordingButton->setDisabled(true);
|
||||||
m_pausePlaybackButton->setDisabled(true);
|
m_pausePlaybackButton->setDisabled(true);
|
||||||
|
m_deviceListCB->setEnabled(true);
|
||||||
|
m_refreshDevicesButton->setEnabled(true);
|
||||||
|
m_comboSamplerate->setEnabled(true);
|
||||||
|
m_comboSamplefmt->setEnabled(true);
|
||||||
m_recordedLevels.clear();
|
m_recordedLevels.clear();
|
||||||
m_duration->setText("00:00");
|
m_duration->setText("00:00.000");
|
||||||
m_playDuration->setText("00:00");
|
m_playDuration->setText("00:00.000");
|
||||||
m_audioLevelsDisplay->setLevel(0);
|
m_audioLevelsDisplay->setLevel(-1);
|
||||||
|
if (!m_console) {
|
||||||
|
m_console = FlipConsole::getCurrent();
|
||||||
|
if (m_console)
|
||||||
|
connect(m_console, SIGNAL(playStateChanged(bool)), this,
|
||||||
|
SLOT(onPlayStateChanged(bool)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void AudioRecordingPopup::hideEvent(QHideEvent *event) {
|
void AudioRecordingPopup::hideEvent(QHideEvent *event) {
|
||||||
if (m_audioRecorder->state() != QAudioRecorder::StoppedState) {
|
if (m_audioInput->state() != QAudio::StoppedState) {
|
||||||
m_audioRecorder->stop();
|
m_audioInput->stop();
|
||||||
}
|
}
|
||||||
if (m_player->state() != QMediaPlayer::StoppedState) {
|
if (m_player->state() != QMediaPlayer::StoppedState) {
|
||||||
m_player->stop();
|
m_player->stop();
|
||||||
}
|
}
|
||||||
// make sure the file is freed before deleting
|
// make sure the file is freed before deleting
|
||||||
|
delete m_player;
|
||||||
m_player = new QMediaPlayer(this);
|
m_player = new QMediaPlayer(this);
|
||||||
// this should only remove files that haven't been used in the scene
|
// this should only remove files that haven't been used in the scene
|
||||||
// make paths checks to only create path names that don't exist yet.
|
// make paths checks to only create path names that don't exist yet.
|
||||||
|
@ -569,6 +628,172 @@ void AudioRecordingPopup::hideEvent(QHideEvent *event) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AudioRecordingPopup::enumerateAudioDevices(const QString &selectedDeviceName) {
|
||||||
|
const QAudioDeviceInfo &defaultDeviceInfo =
|
||||||
|
QAudioDeviceInfo::defaultInputDevice();
|
||||||
|
|
||||||
|
m_blockAudioSettings = true;
|
||||||
|
m_deviceListCB->clear();
|
||||||
|
m_deviceListCB->addItem(defaultDeviceInfo.deviceName(),
|
||||||
|
QVariant::fromValue(defaultDeviceInfo));
|
||||||
|
|
||||||
|
for (auto &deviceInfo :
|
||||||
|
QAudioDeviceInfo::availableDevices(QAudio::AudioInput)) {
|
||||||
|
if (deviceInfo != defaultDeviceInfo &&
|
||||||
|
m_deviceListCB->findText(deviceInfo.deviceName()) == -1) {
|
||||||
|
m_deviceListCB->addItem(deviceInfo.deviceName(),
|
||||||
|
QVariant::fromValue(deviceInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int deviceIndex = m_deviceListCB->findText(selectedDeviceName);
|
||||||
|
if (deviceIndex != -1) m_deviceListCB->setCurrentIndex(deviceIndex);
|
||||||
|
m_blockAudioSettings = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void AudioRecordingPopup::reinitAudioInput() {
|
||||||
|
if (m_blockAudioSettings) return;
|
||||||
|
|
||||||
|
QAudioDeviceInfo m_audioDeviceInfo =
|
||||||
|
m_deviceListCB->itemData(m_deviceListCB->currentIndex())
|
||||||
|
.value<QAudioDeviceInfo>();
|
||||||
|
int samplerate =
|
||||||
|
m_comboSamplerate->itemData(m_comboSamplerate->currentIndex())
|
||||||
|
.value<int>();
|
||||||
|
int sampletype =
|
||||||
|
m_comboSamplefmt->itemData(m_comboSamplefmt->currentIndex()).value<int>();
|
||||||
|
int bitdepth = sampletype & 56;
|
||||||
|
int channels = sampletype & 7;
|
||||||
|
|
||||||
|
QAudioFormat format;
|
||||||
|
format.setSampleRate(samplerate);
|
||||||
|
format.setChannelCount(channels);
|
||||||
|
format.setSampleSize(bitdepth);
|
||||||
|
format.setSampleType(bitdepth == 8 ? QAudioFormat::UnSignedInt
|
||||||
|
: QAudioFormat::SignedInt);
|
||||||
|
format.setByteOrder(QAudioFormat::LittleEndian);
|
||||||
|
format.setCodec("audio/pcm");
|
||||||
|
if (!m_audioDeviceInfo.isFormatSupported(format)) {
|
||||||
|
DVGui::warning(tr(
|
||||||
|
"Audio format unsupported:\nNearest format will be internally used."));
|
||||||
|
format = m_audioDeviceInfo.nearestFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recreate input
|
||||||
|
delete m_audioInput;
|
||||||
|
m_audioInput = new QAudioInput(m_audioDeviceInfo, format);
|
||||||
|
m_audioWriterWAV->restart(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// AudioWriterWAV Class
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// IODevice to write standard WAV files, performs peak level calc
|
||||||
|
//
|
||||||
|
// 8-bits audio must be unsigned
|
||||||
|
// 16-bits audio must be signed
|
||||||
|
// 32-bits isn't supported
|
||||||
|
|
||||||
|
AudioWriterWAV::AudioWriterWAV(const QAudioFormat &format)
|
||||||
|
: m_level(0.0), m_maxAmp(0.0) {
|
||||||
|
restart(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioWriterWAV::restart(const QAudioFormat &format) {
|
||||||
|
m_format = format;
|
||||||
|
if (m_format.sampleSize() == 8) {
|
||||||
|
m_rbytesms = 1000.0 / (m_format.sampleRate() * m_format.channelCount());
|
||||||
|
m_maxAmp = 127.0;
|
||||||
|
} else if (m_format.sampleSize() == 16) {
|
||||||
|
m_rbytesms = 500.0 / (m_format.sampleRate() * m_format.channelCount());
|
||||||
|
m_maxAmp = 32767.0;
|
||||||
|
} else {
|
||||||
|
// 32-bits isn't supported
|
||||||
|
m_rbytesms = 250.0 / (m_format.sampleRate() * m_format.channelCount());
|
||||||
|
m_maxAmp = 1.0;
|
||||||
|
}
|
||||||
|
m_barray.clear();
|
||||||
|
return this->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioWriterWAV::start() {
|
||||||
|
open(QIODevice::WriteOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioWriterWAV::stop() {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 AudioWriterWAV::readData(char *data, qint64 maxlen) {
|
||||||
|
Q_UNUSED(data)
|
||||||
|
Q_UNUSED(maxlen)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 AudioWriterWAV::writeData(const char *data, qint64 len) {
|
||||||
|
qreal tmp, peak = 0.0;
|
||||||
|
|
||||||
|
// Measure peak
|
||||||
|
if (m_format.sampleSize() == 8) {
|
||||||
|
const quint8 *sdata = (const quint8 *)data;
|
||||||
|
int slen = len;
|
||||||
|
for (int i = 0; i < slen; ++i) {
|
||||||
|
tmp = qAbs(qreal(sdata[i]) - 128.0);
|
||||||
|
if (tmp > peak) peak = tmp;
|
||||||
|
}
|
||||||
|
} else if (m_format.sampleSize() == 16) {
|
||||||
|
const qint16 *sdata = (const qint16 *)data;
|
||||||
|
int slen = len / 2;
|
||||||
|
for (int i = 0; i < slen; ++i) {
|
||||||
|
tmp = qAbs(qreal(sdata[i]));
|
||||||
|
if (tmp > peak) peak = tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 32-bits isn't supported
|
||||||
|
peak = -1.0;
|
||||||
|
}
|
||||||
|
m_level = peak / m_maxAmp;
|
||||||
|
|
||||||
|
// Write to buffer
|
||||||
|
m_barray.append(data, len);
|
||||||
|
|
||||||
|
// Emit an update
|
||||||
|
emit update(m_barray.size() * m_rbytesms);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioWriterWAV::save(const QString &filename)
|
||||||
|
{
|
||||||
|
QFile file;
|
||||||
|
quint16 channels = m_format.channelCount();
|
||||||
|
quint32 samplerate = m_format.sampleRate();
|
||||||
|
quint16 bitrate = m_format.sampleSize();
|
||||||
|
file.setFileName(filename);
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||||
|
DVGui::warning(tr(
|
||||||
|
"Failed to save WAV file:\nMake sure you have folder permissions."));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
QDataStream out(&file);
|
||||||
|
out.setByteOrder(QDataStream::LittleEndian);
|
||||||
|
out.writeRawData("RIFF", 4);
|
||||||
|
out << (quint32)(m_barray.size() + 44);
|
||||||
|
out.writeRawData("WAVEfmt ", 8);
|
||||||
|
out << (quint32)16 << (quint16)1;
|
||||||
|
out << channels << samplerate;
|
||||||
|
out << quint32(samplerate * channels * bitrate / 8);
|
||||||
|
out << quint16(channels * bitrate / 8);
|
||||||
|
out << bitrate;
|
||||||
|
out.writeRawData("data", 4);
|
||||||
|
out << (quint32)m_barray.size();
|
||||||
|
out.writeRawData(m_barray.constData(), m_barray.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// AudioLevelsDisplay Class
|
// AudioLevelsDisplay Class
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -591,11 +816,11 @@ void AudioLevelsDisplay::paintEvent(QPaintEvent *event) {
|
||||||
|
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
QColor color;
|
QColor color;
|
||||||
if (m_level < 0.5) {
|
if (m_level < 0.0) {
|
||||||
|
return; // draw nothing...
|
||||||
|
} else if (m_level < 0.5) {
|
||||||
color = Qt::green;
|
color = Qt::green;
|
||||||
}
|
} else if (m_level < 0.75) {
|
||||||
|
|
||||||
else if (m_level < 0.75) {
|
|
||||||
color = QColor(204, 205, 0); // yellow
|
color = QColor(204, 205, 0); // yellow
|
||||||
} else if (m_level < 0.95) {
|
} else if (m_level < 0.95) {
|
||||||
color = QColor(255, 115, 0); // orange
|
color = QColor(255, 115, 0); // orange
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QAudioRecorder;
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
class AudioLevelsDisplay;
|
class AudioLevelsDisplay;
|
||||||
class FlipConsole;
|
class FlipConsole;
|
||||||
|
@ -23,6 +22,7 @@ class QAudioProbe;
|
||||||
class QAudioBuffer;
|
class QAudioBuffer;
|
||||||
class QMediaPlayer;
|
class QMediaPlayer;
|
||||||
class QElapsedTimer;
|
class QElapsedTimer;
|
||||||
|
class AudioWriterWAV;
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// AudioRecordingPopup
|
// AudioRecordingPopup
|
||||||
|
@ -31,13 +31,13 @@ class QElapsedTimer;
|
||||||
class AudioRecordingPopup : public DVGui::Dialog {
|
class AudioRecordingPopup : public DVGui::Dialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
QString m_deviceName;
|
|
||||||
QPushButton
|
QPushButton
|
||||||
*m_recordButton, // *m_refreshDevicesButton, -refresh not working for now
|
*m_recordButton, *m_refreshDevicesButton,
|
||||||
*m_playButton,
|
*m_playButton,
|
||||||
*m_pauseRecordingButton, *m_pausePlaybackButton, *m_saveButton;
|
*m_pauseRecordingButton, *m_pausePlaybackButton, *m_saveButton;
|
||||||
QComboBox *m_deviceListCB;
|
QComboBox *m_deviceListCB;
|
||||||
QAudioRecorder *m_audioRecorder;
|
QAudioInput *m_audioInput;
|
||||||
|
AudioWriterWAV *m_audioWriterWAV;
|
||||||
QLabel *m_duration, *m_playDuration;
|
QLabel *m_duration, *m_playDuration;
|
||||||
QCheckBox *m_playXSheetCB;
|
QCheckBox *m_playXSheetCB;
|
||||||
int m_currentFrame;
|
int m_currentFrame;
|
||||||
|
@ -56,7 +56,11 @@ class AudioRecordingPopup : public DVGui::Dialog {
|
||||||
QIcon m_pauseIcon;
|
QIcon m_pauseIcon;
|
||||||
QIcon m_recordIcon;
|
QIcon m_recordIcon;
|
||||||
QIcon m_stopIcon;
|
QIcon m_stopIcon;
|
||||||
|
QIcon m_refreshIcon;
|
||||||
bool m_isPlaying, m_syncPlayback, m_stoppedAtEnd;
|
bool m_isPlaying, m_syncPlayback, m_stoppedAtEnd;
|
||||||
|
QLabel *m_labelDevice, *m_labelSamplerate, *m_labelSamplefmt;
|
||||||
|
QComboBox *m_comboSamplerate, *m_comboSamplefmt;
|
||||||
|
bool m_blockAudioSettings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioRecordingPopup();
|
AudioRecordingPopup();
|
||||||
|
@ -67,6 +71,8 @@ protected:
|
||||||
void hideEvent(QHideEvent *event);
|
void hideEvent(QHideEvent *event);
|
||||||
void makePaths();
|
void makePaths();
|
||||||
void resetEverything();
|
void resetEverything();
|
||||||
|
void enumerateAudioDevices(const QString &deviceName);
|
||||||
|
void reinitAudioInput();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRecordButtonPressed();
|
void onRecordButtonPressed();
|
||||||
|
@ -76,12 +82,42 @@ private slots:
|
||||||
void onSaveButtonPressed();
|
void onSaveButtonPressed();
|
||||||
void onPauseRecordingButtonPressed();
|
void onPauseRecordingButtonPressed();
|
||||||
void onPausePlaybackButtonPressed();
|
void onPausePlaybackButtonPressed();
|
||||||
void processBuffer(const QAudioBuffer &buffer);
|
|
||||||
void onPlayStateChanged(bool playing);
|
void onPlayStateChanged(bool playing);
|
||||||
void onPlayXSheetCBChanged(int status);
|
void onPlayXSheetCBChanged(int status);
|
||||||
void onMediaStateChanged(QMediaPlayer::State state);
|
void onMediaStateChanged(QMediaPlayer::State state);
|
||||||
void onInputDeviceChanged();
|
void onInputDeviceChanged();
|
||||||
// void onRefreshButtonPressed();
|
void onRefreshButtonPressed();
|
||||||
|
void onAudioSettingChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// AudioWriterWAV
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class AudioWriterWAV : public QIODevice {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
AudioWriterWAV(const QAudioFormat &format);
|
||||||
|
bool restart(const QAudioFormat &format);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
bool save(const QString &filename);
|
||||||
|
|
||||||
|
qint64 readData(char *data, qint64 maxlen) override;
|
||||||
|
qint64 writeData(const char *data, qint64 len) override;
|
||||||
|
|
||||||
|
qreal level() const { return m_level; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QByteArray m_barray;
|
||||||
|
QAudioFormat m_format;
|
||||||
|
qreal m_rbytesms;
|
||||||
|
qreal m_maxAmp;
|
||||||
|
qreal m_level;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void update(qint64 duration);
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
Loading…
Reference in a new issue