Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
Binary file added src/.DS_Store
Binary file not shown.
3 changes: 2 additions & 1 deletion src/encoder/encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class Encoder {
Encoder() {}
virtual ~Encoder() = default;

virtual int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) = 0;
virtual int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) = 0;
// encodes the provided buffer of audio.
virtual void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) = 0;
// Adds metadata to the encoded audio, i.e., the ID3 tag. Currently only used
Expand Down
3 changes: 2 additions & 1 deletion src/encoder/encoderfdkaac.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,8 @@ void EncoderFdkAac::setEncoderSettings(const EncoderSettings& settings) {
}
}

int EncoderFdkAac::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
int EncoderFdkAac::initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) {
m_sampleRate = sampleRate;

if (!m_pLibrary) {
Expand Down
3 changes: 2 additions & 1 deletion src/encoder/encoderfdkaac.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class EncoderFdkAac : public Encoder {
EncoderFdkAac(EncoderCallback* pCallback);
virtual ~EncoderFdkAac();

int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override;
int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) override;
void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) override;
void updateMetaData(const QString& artist, const QString& title, const QString& album) override;
void flush() override;
Expand Down
6 changes: 6 additions & 0 deletions src/encoder/encoderfdkaacsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,10 @@ class EncoderFdkAacSettings : public EncoderRecordingSettings {
QList<int> m_qualList;
UserSettingsPointer m_pConfig;
QString m_format;

protected:
// Provide config to base class
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
6 changes: 6 additions & 0 deletions src/encoder/encoderflacsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,10 @@ class EncoderFlacSettings : public EncoderRecordingSettings {
QList<OptionsGroup> m_radioList;
QList<int> m_qualList;
UserSettingsPointer m_pConfig;

protected:
// Provide config to base class
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
18 changes: 16 additions & 2 deletions src/encoder/encodermp3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ void EncoderMp3::initStream() {
m_bufferIn[1] = (float *)malloc(m_bufferOutSize * sizeof(float));
}

int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) {
unsigned long samplerate_in = sampleRate;
// samplerate_out 0 means "let LAME pick the appropriate one"
unsigned long samplerate_out = (samplerate_in > 48000 ? 48000 : 0);
Expand All @@ -199,11 +200,24 @@ int EncoderMp3::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserE
lame_set_out_samplerate(m_lameFlags, samplerate_out);

// Input channels into the encoder
lame_set_num_channels(m_lameFlags, 2);
int channels = (m_stereo_mode == MONO) ? 1 : 2;
lame_set_num_channels(m_lameFlags, channels);
// Output channels (on the mp3 file)
// mode = 0,1,2,3 = stereo, jstereo, dual channel (not supported), mono
// Note: JOINT_STEREO is not "forced joint stereo" (That is lame_set_force_ms )
if (channels == 1) {
m_stereo_mode = MONO;
qDebug() << "EncoderMp3: forcing MONO (channels = 1)";
} else {
// channels == 2
m_stereo_mode = JOINT_STEREO;
qDebug() << "EncoderMp3: stereo encoding (channels = 2)";
}
lame_set_mode(m_lameFlags, m_stereo_mode);
qDebug() << "EncoderMp3::initEncoder"
<< "sampleRate =" << samplerate_in
<< "channels =" << channels
<< "mode =" << m_stereo_mode;

if (m_encoding_mode == vbr_off) {
qDebug() << " CBR mode with bitrate: " << m_bitrate;
Expand Down
3 changes: 2 additions & 1 deletion src/encoder/encodermp3.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class EncoderMp3 final : public Encoder {
EncoderMp3(EncoderCallback* callback=nullptr);
~EncoderMp3() override;

int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override;
int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) override;
void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) override;
void updateMetaData(const QString& artist, const QString& title, const QString& album) override;
void flush() override;
Expand Down
6 changes: 6 additions & 0 deletions src/encoder/encodermp3settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,10 @@ class EncoderMp3Settings : public EncoderRecordingSettings {
QList<int> m_qualList;
QList<int> m_qualVBRList;
UserSettingsPointer m_pConfig;

protected:
// Provide config to base class to read channel mode from recording preferences
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
3 changes: 2 additions & 1 deletion src/encoder/encoderopus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ void EncoderOpus::setEncoderSettings(const EncoderSettings& settings) {
}
}

int EncoderOpus::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
int EncoderOpus::initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) {
Q_UNUSED(pUserErrorMessage);

if (sampleRate != kMainSampleRate) {
Expand Down
3 changes: 2 additions & 1 deletion src/encoder/encoderopus.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class EncoderOpus: public Encoder {
explicit EncoderOpus(EncoderCallback* pCallback = nullptr);
~EncoderOpus() override;

int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override;
int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) override;
void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) override;
void updateMetaData(const QString& artist, const QString& title, const QString& album) override;
void flush() override;
Expand Down
6 changes: 6 additions & 0 deletions src/encoder/encoderopussettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,10 @@ class EncoderOpusSettings: public EncoderRecordingSettings {
UserSettingsPointer m_pConfig;
QList<int> m_qualList;
QList<OptionsGroup> m_radioList;

protected:
// Provide config to base class
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
31 changes: 31 additions & 0 deletions src/encoder/encoderrecordingsettings.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include "encoder/encodersettings.h"
#include "preferences/usersettings.h"
#include "recording/defs_recording.h"
#include "util/assert.h"

class EncoderRecordingSettings : public EncoderSettings {
Expand Down Expand Up @@ -33,6 +35,35 @@ class EncoderRecordingSettings : public EncoderSettings {
Q_UNUSED(optionIndex);
DEBUG_ASSERT(!"unimplemented");
}

// Override getChannelMode to read from recording preferences but making it
// so that it fallbacks to stereo if no config is available (e.g. in
// broadcasting context)
ChannelMode getChannelMode() const override {
UserSettingsPointer config = getConfig();
if (!config) {
// Fallback if no config (shouldn't happen in recording context)
return ChannelMode::STEREO;
}

int channelMode = config->getValue<int>(
ConfigKey(RECORDING_PREF_KEY, "channel_mode"), 0);

switch (channelMode) {
case 1:
return ChannelMode::MONO;
case 0: // fallthrough
default:
return ChannelMode::STEREO;
}
}

protected:
// Subclasses override this to provide their m_pConfig
// Base class returns null pointer
virtual UserSettingsPointer getConfig() const {
return UserSettingsPointer();
}
};

typedef std::shared_ptr<EncoderRecordingSettings> EncoderRecordingSettingsPointer;
3 changes: 2 additions & 1 deletion src/encoder/encodervorbis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ void EncoderVorbis::initStream() {
m_bStreamInitialized = true;
}

int EncoderVorbis::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
int EncoderVorbis::initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) {
vorbis_info_init(&m_vinfo);

// initialize VBR quality based mode
Expand Down
3 changes: 2 additions & 1 deletion src/encoder/encodervorbis.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class EncoderVorbis : public Encoder {
EncoderVorbis(EncoderCallback* pCallback = nullptr);
~EncoderVorbis() override;

int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override;
int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) override;
void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) override;
void updateMetaData(const QString& artist, const QString& title, const QString& album) override;
void flush() override;
Expand Down
6 changes: 6 additions & 0 deletions src/encoder/encodervorbissettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,10 @@ class EncoderVorbisSettings : public EncoderRecordingSettings {
private:
QList<int> m_qualList;
UserSettingsPointer m_pConfig;

protected:
// Provide config to base class to read channel mode from recording preferences
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
24 changes: 18 additions & 6 deletions src/encoder/encoderwave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,10 @@ static sf_count_t sf_f_tell (void *user_data)
return pCallback->tell();
}




EncoderWave::EncoderWave(EncoderCallback* pCallback)
: m_pCallback(pCallback),
m_pSndfile(nullptr) {
m_pSndfile(nullptr),
m_channels(2) {
m_sfInfo.frames = 0;
m_sfInfo.samplerate = 0;
m_sfInfo.channels = 0;
Expand Down Expand Up @@ -129,6 +127,19 @@ void EncoderWave::setEncoderSettings(const EncoderSettings& settings) {
<< radio << ". reverting to PCM 16bits";
break;
}

// Read channel mode from settings
switch (settings.getChannelMode()) {
case EncoderSettings::ChannelMode::MONO:
m_channels = 1;
break;
case EncoderSettings::ChannelMode::STEREO:
m_channels = 2;
break;
case EncoderSettings::ChannelMode::AUTOMATIC:
m_channels = 2;
break;
}
}

// call sendPackages() or write() after 'flush()' as outlined in enginebroadcast.cpp
Expand Down Expand Up @@ -193,12 +204,13 @@ void EncoderWave::initStream() {
}
}

int EncoderWave::initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) {
int EncoderWave::initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) {
Q_UNUSED(pUserErrorMessage);
// set sfInfo.
// m_sfInfo.format is setup on setEncoderSettings previous to calling initEncoder.
m_sfInfo.samplerate = sampleRate;
m_sfInfo.channels = 2;
m_sfInfo.channels = m_channels;
m_sfInfo.frames = 0;
m_sfInfo.sections = 0;
m_sfInfo.seekable = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/encoder/encoderwave.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class EncoderWave : public Encoder {
EncoderWave(EncoderCallback* pCallback = nullptr);
~EncoderWave() override;

int initEncoder(mixxx::audio::SampleRate sampleRate, QString* pUserErrorMessage) override;
int initEncoder(mixxx::audio::SampleRate sampleRate,
QString* pUserErrorMessage) override;
void encodeBuffer(const CSAMPLE* samples, const std::size_t bufferSize) override;
void updateMetaData(const QString& artist, const QString& title, const QString& album) override;
void flush() override;
Expand All @@ -36,6 +37,6 @@ class EncoderWave : public Encoder {

SNDFILE* m_pSndfile;
SF_INFO m_sfInfo;

SF_VIRTUAL_IO m_virtualIo;
int m_channels;
};
6 changes: 6 additions & 0 deletions src/encoder/encoderwavesettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ class EncoderWaveSettings : public EncoderRecordingSettings {
QList<OptionsGroup> m_radioList;
UserSettingsPointer m_pConfig;
QString m_format;

protected:
// Provide config to base class
UserSettingsPointer getConfig() const override {
return m_pConfig;
}
};
Binary file added src/engine/.DS_Store
Binary file not shown.
31 changes: 27 additions & 4 deletions src/engine/sidechain/enginerecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
#include "recording/defs_recording.h"
#include "track/track.h"
#include "util/event.h"
#include "util/sample.h" //Using MixMultiChanneltomono function to convert stereo to mono

constexpr int kMetaDataLifeTimeout = 16;

EngineRecord::EngineRecord(UserSettingsPointer pConfig)
: m_pConfig(pConfig),
m_sampleRateControl(QStringLiteral("[App]"), QStringLiteral("samplerate")),
m_sampleRateControl(
QStringLiteral("[App]"), QStringLiteral("samplerate")),
m_frames(0),
m_recordedDuration(0),
m_iMetaDataLife(0),
m_cueTrack(0),
m_bCueIsEnabled(false),
m_bCueUsesFileAnnotation(false) {
m_bCueUsesFileAnnotation(
false) { // defaulting to stereo but not picking from config
// in case config is not yet loaded
m_pRecReady = new ControlProxy(RECORDING_PREF_KEY, "status", this);
m_sampleRate = mixxx::audio::SampleRate::fromDouble(m_sampleRateControl.get());
}
Expand All @@ -36,6 +40,7 @@ int EngineRecord::updateFromPreferences() {
m_baAuthor = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Author"));
m_baAlbum = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "Album"));
m_cueFileName = m_pConfig->getValueString(ConfigKey(RECORDING_PREF_KEY, "CuePath"));

m_bCueIsEnabled = m_pConfig->getValue<bool>(
ConfigKey(RECORDING_PREF_KEY, QStringLiteral("CueEnabled")));
m_bCueUsesFileAnnotation = m_pConfig->getValue<bool>(
Expand Down Expand Up @@ -202,9 +207,27 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const std::size_t bufferSize)
// Checking again from m_pRecReady since its status might have changed
// in the previous "if" blocks.
if (m_pRecReady->get() == RECORD_ON) {
int channelMode = m_pConfig->getValue<int>(
ConfigKey(RECORDING_PREF_KEY, "channel_mode"), 0);
bool recordMono = (channelMode == 1);
/* Downmixing audio to mono if mono recording is enabled.
We need to do it before encoding because some encoders don't support mono
and we want to be able to record in mono even with these encoders.*/
const CSAMPLE* bufferToEncode = pBuffer;
std::vector<CSAMPLE> monoBuffer;
std::size_t encoderBufferSize = bufferSize;

if (recordMono) {
// Allocate mono buffer (half the size since we're going from 2 channels to 1)
monoBuffer.resize(bufferSize / 2);
SampleUtil::mixMultichannelToMono(monoBuffer.data(), pBuffer, bufferSize);
bufferToEncode = monoBuffer.data();
encoderBufferSize = bufferSize / 2;
}

// Compress audio. Encoder will call method 'write()' below to
// write a file stream and emit bytesRecorded.
m_pEncoder->encodeBuffer(pBuffer, bufferSize);
m_pEncoder->encodeBuffer(bufferToEncode, encoderBufferSize);

//Writing cueLine before updating the time counter since we prefer to be ahead
//rather than late.
Expand All @@ -215,7 +238,7 @@ void EngineRecord::process(const CSAMPLE* pBuffer, const std::size_t bufferSize)
}

// update frames counting and recorded duration (seconds)
m_frames += bufferSize / 2;
m_frames += encoderBufferSize / 2;
unsigned long lastDuration = m_recordedDuration;
m_recordedDuration = m_frames / m_sampleRate;

Expand Down
1 change: 1 addition & 0 deletions src/engine/sidechain/enginerecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "control/pollingcontrolproxy.h"
#include "encoder/encoder.h"
#include "encoder/encodercallback.h"
#include "encoder/encodersettings.h"
#include "engine/sidechain/sidechainworker.h"
#include "preferences/usersettings.h"
#include "track/track_decl.h"
Expand Down
Loading
Loading