Allow the option to select sample rate to stream at rather than have it hard coded to 48000hz

This commit is contained in:
jp9000 2013-09-02 18:40:15 -07:00
parent 8fd7282cb8
commit 3520b15ca4
13 changed files with 51 additions and 26 deletions

View File

@ -74,8 +74,7 @@ void NoiseGateFilter::ApplyNoiseGate(float *buffer, int totalFloats)
if(totalFloats % 2) if(totalFloats % 2)
return; // Odd number of samples return; // Odd number of samples
// OBS is currently hard-coded to 48ksps const float SAMPLE_RATE_F = float(OBSGetSampleRateHz());
const float SAMPLE_RATE_F = 48000.0f;
const float dtPerSample = 1.0f / SAMPLE_RATE_F; const float dtPerSample = 1.0f / SAMPLE_RATE_F;
// Convert configuration times into per-sample amounts // Convert configuration times into per-sample amounts
@ -83,10 +82,9 @@ void NoiseGateFilter::ApplyNoiseGate(float *buffer, int totalFloats)
const float releaseRate = 1.0f / (parent->releaseTime * SAMPLE_RATE_F); const float releaseRate = 1.0f / (parent->releaseTime * SAMPLE_RATE_F);
// Determine level decay rate. We don't want human voice (75-300Hz) to cross the close // Determine level decay rate. We don't want human voice (75-300Hz) to cross the close
// threshold if the previous peak crosses the open threshold. 75Hz at 48ksps is 640 // threshold if the previous peak crosses the open threshold.
// samples between peaks.
const float thresholdDiff = parent->openThreshold - parent->closeThreshold; const float thresholdDiff = parent->openThreshold - parent->closeThreshold;
const float minDecayPeriod = (1.0f / 75.0f) * SAMPLE_RATE_F; // 640 samples const float minDecayPeriod = (1.0f / 75.0f) * SAMPLE_RATE_F;
const float decayRate = thresholdDiff / minDecayPeriod; const float decayRate = thresholdDiff / minDecayPeriod;
// We can't use SSE as the processing of each sample depends on the processed // We can't use SSE as the processing of each sample depends on the processed

2
OBS.rc
View File

@ -126,7 +126,7 @@ BEGIN
RTEXT "Settings.Encoding.Audio.Bitrate",IDC_STATIC,221,85,128,8 RTEXT "Settings.Encoding.Audio.Bitrate",IDC_STATIC,221,85,128,8
COMBOBOX IDC_AUDIOBITRATE,354,83,61,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_AUDIOBITRATE,354,83,61,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
RTEXT "Settings.Encoding.Audio.Format",IDC_STATIC,10,101,138,8 RTEXT "Settings.Encoding.Audio.Format",IDC_STATIC,10,101,138,8
COMBOBOX IDC_AUDIOFORMAT,152,99,264,62,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_AUDIOFORMAT,152,99,264,62,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Settings.Info",IDC_INFO,4,122,417,37,NOT WS_VISIBLE LTEXT "Settings.Info",IDC_INFO,4,122,417,37,NOT WS_VISIBLE
END END

View File

@ -141,4 +141,6 @@ void OBSGetCurMicVolumeStats(float *rms, float *max, float *peak) {API->Ge
void OBSAddSettingsPane(SettingsPane *pane) {API->AddSettingsPane(pane);} void OBSAddSettingsPane(SettingsPane *pane) {API->AddSettingsPane(pane);}
void OBSRemoveSettingsPane(SettingsPane *pane) {API->RemoveSettingsPane(pane);} void OBSRemoveSettingsPane(SettingsPane *pane) {API->RemoveSettingsPane(pane);}
UINT OBSGetAPIVersion() {return 0x0100;} UINT OBSGetAPIVersion() {return 0x0101;}
UINT OBSGetSampleRateHz() {return API->GetSampleRateHz();}

View File

@ -172,6 +172,8 @@ public:
virtual Vect2 MapFrameToWindowSize(Vect2 frameSize) const=0; virtual Vect2 MapFrameToWindowSize(Vect2 frameSize) const=0;
virtual Vect2 GetWindowToFrameScale() const=0; virtual Vect2 GetWindowToFrameScale() const=0;
virtual Vect2 GetFrameToWindowScale() const=0; virtual Vect2 GetFrameToWindowScale() const=0;
virtual UINT GetSampleRateHz() const=0;
}; };
BASE_EXPORT extern APIInterface *API; BASE_EXPORT extern APIInterface *API;
@ -286,3 +288,5 @@ BASE_EXPORT void OBSRemoveSettingsPane(SettingsPane *pane);
/** gets API version. version is formatted: 0xMMmm */ /** gets API version. version is formatted: 0xMMmm */
BASE_EXPORT UINT OBSGetAPIVersion(); BASE_EXPORT UINT OBSGetAPIVersion();
BASE_EXPORT UINT OBSGetSampleRateHz();

View File

@ -87,7 +87,9 @@ void AudioSource::InitAudioData(bool bFloat, UINT channels, UINT samplesPerSec,
//----------------------------- //-----------------------------
if(inputSamplesPerSec != 48000) UINT sampleRateHz = OBSGetSampleRateHz();
if(inputSamplesPerSec != sampleRateHz)
{ {
int errVal; int errVal;
@ -96,12 +98,11 @@ void AudioSource::InitAudioData(bool bFloat, UINT channels, UINT samplesPerSec,
if(!resampler) if(!resampler)
CrashError(TEXT("AudioSource::InitAudioData: Could not initiate resampler")); CrashError(TEXT("AudioSource::InitAudioData: Could not initiate resampler"));
resampleRatio = 48000.0 / double(inputSamplesPerSec); resampleRatio = double(sampleRateHz) / double(inputSamplesPerSec);
bResample = true; bResample = true;
//---------------------------------------------------- //----------------------------------------------------
// hack to get rid of that weird first quirky resampled packet size // hack to get rid of that weird first quirky resampled packet size
// (always returns a non-480 sized packet on the first resample)
SRC_DATA data; SRC_DATA data;
data.src_ratio = resampleRatio; data.src_ratio = resampleRatio;
@ -679,7 +680,7 @@ bool AudioSource::GetBuffer(float **buffer, QWORD targetTimestamp)
} }
} }
outputBuffer.SetSize(480*2); outputBuffer.SetSize(OBSGetSampleRateHz()/100*2);
*buffer = outputBuffer.Array(); *buffer = outputBuffer.Array();

View File

@ -539,6 +539,8 @@ public:
virtual void AddSettingsPane(SettingsPane *pane) {App->AddSettingsPane(pane);} virtual void AddSettingsPane(SettingsPane *pane) {App->AddSettingsPane(pane);}
virtual void RemoveSettingsPane(SettingsPane *pane) {App->RemoveSettingsPane(pane);} virtual void RemoveSettingsPane(SettingsPane *pane) {App->RemoveSettingsPane(pane);}
virtual UINT GetSampleRateHz() const {return App->GetSampleRateHz();}
}; };
APIInterface* CreateOBSApiInterface() APIInterface* CreateOBSApiInterface()

View File

@ -46,7 +46,7 @@ public:
{ {
curBitRate = bitRate; curBitRate = bitRate;
faac = faacEncOpen(48000, 2, &numReadSamples, &outputSize); faac = faacEncOpen(App->GetSampleRateHz(), 2, &numReadSamples, &outputSize);
//Log(TEXT("numReadSamples: %d"), numReadSamples); //Log(TEXT("numReadSamples: %d"), numReadSamples);
aacBuffer.SetSize(outputSize+2); aacBuffer.SetSize(outputSize+2);
@ -155,7 +155,7 @@ public:
inputBuffer.RemoveRange(0, numReadSamples); inputBuffer.RemoveRange(0, numReadSamples);
bufferedTimestamps << curEncodeTimestamp; bufferedTimestamps << curEncodeTimestamp;
curEncodeTimestamp = curTimestamp + (((numReadSamples-lastSampleSize)/2)/48); curEncodeTimestamp = curTimestamp + (((numReadSamples-lastSampleSize)/2)*1000/App->GetSampleRateHz());
} }
return ret > 0; return ret > 0;

View File

@ -59,8 +59,8 @@ public:
if(!lgf) if(!lgf)
CrashError(TEXT("Unable to open mp3 encoder")); CrashError(TEXT("Unable to open mp3 encoder"));
lame_set_in_samplerate(lgf, 48000); lame_set_in_samplerate(lgf, App->GetSampleRateHz());
lame_set_out_samplerate(lgf, 48000); lame_set_out_samplerate(lgf, App->GetSampleRateHz());
lame_set_num_channels(lgf, 2); lame_set_num_channels(lgf, 2);
lame_set_mode(lgf, STEREO); lame_set_mode(lgf, STEREO);
lame_set_disable_reservoir(lgf, TRUE); //bit reservoir has to be disabled for seamless streaming lame_set_disable_reservoir(lgf, TRUE); //bit reservoir has to be disabled for seamless streaming
@ -102,7 +102,7 @@ public:
frameCounter -= outputFrameSize; frameCounter -= outputFrameSize;
bufferedTimestamps << curEncodeTimestamp; bufferedTimestamps << curEncodeTimestamp;
curEncodeTimestamp = timestamp + ((outputFrameSize-lastSampleSize)/48); curEncodeTimestamp = timestamp + ((outputFrameSize-lastSampleSize)*1000/App->GetSampleRateHz());
} }
int ret = lame_encode_buffer_interleaved_ieee_float(lgf, (float*)input, numInputFrames, MP3OutputBuffer.Array()+1, dwMP3MaxSize); int ret = lame_encode_buffer_interleaved_ieee_float(lgf, (float*)input, numInputFrames, MP3OutputBuffer.Array()+1, dwMP3MaxSize);

View File

@ -57,7 +57,7 @@ struct MP4AudioFrameInfo
inline UINT64 ConvertToAudioTime(DWORD timestamp, UINT64 minVal) inline UINT64 ConvertToAudioTime(DWORD timestamp, UINT64 minVal)
{ {
UINT val = UINT64(timestamp)*48000/1000; UINT val = UINT64(timestamp)*App->GetSampleRateHz()/1000;
return MAX(val, minVal); return MAX(val, minVal);
} }
@ -303,7 +303,7 @@ public:
DWORD macTime = fastHtonl(DWORD(GetMacTime())); DWORD macTime = fastHtonl(DWORD(GetMacTime()));
UINT videoDuration = fastHtonl(lastVideoTimestamp + App->GetFrameTime()); UINT videoDuration = fastHtonl(lastVideoTimestamp + App->GetFrameTime());
UINT audioDuration = fastHtonl(lastVideoTimestamp + DWORD(double(audioFrameSize)/48)); UINT audioDuration = fastHtonl(lastVideoTimestamp + DWORD(double(audioFrameSize)*1000.0/double(App->GetSampleRateHz())));
UINT width, height; UINT width, height;
App->GetOutputSize(width, height); App->GetOutputSize(width, height);
@ -453,7 +453,7 @@ public:
output.OutputDword(0); //version and flags (none) output.OutputDword(0); //version and flags (none)
output.OutputDword(macTime); //creation time output.OutputDword(macTime); //creation time
output.OutputDword(macTime); //modified time output.OutputDword(macTime); //modified time
output.OutputDword(DWORD_BE(48000)); //time scale output.OutputDword(DWORD_BE(App->GetSampleRateHz())); //time scale
output.OutputDword(audioUnitDuration); output.OutputDword(audioUnitDuration);
output.OutputDword(bMP3 ? DWORD_BE(0x55c40000) : DWORD_BE(0x15c70000)); output.OutputDword(bMP3 ? DWORD_BE(0x55c40000) : DWORD_BE(0x15c70000));
PopBox(output); //mdhd PopBox(output); //mdhd
@ -495,7 +495,7 @@ public:
output.OutputWord(WORD_BE(16)); //sample size output.OutputWord(WORD_BE(16)); //sample size
output.OutputWord(0); //quicktime audio compression id output.OutputWord(0); //quicktime audio compression id
output.OutputWord(0); //quicktime audio packet size output.OutputWord(0); //quicktime audio packet size
output.OutputDword(DWORD_BE(48000<<16)); //sample rate (fixed point) output.OutputDword(DWORD_BE(App->GetSampleRateHz()<<16)); //sample rate (fixed point)
PushBox(output, DWORD_BE('esds')); PushBox(output, DWORD_BE('esds'));
output.OutputDword(0); //version and flags (none) output.OutputDword(0); //version and flags (none)
output.OutputByte(3); //ES descriptor type output.OutputByte(3); //ES descriptor type

View File

@ -499,6 +499,8 @@ class OBS
AudioSource *micAudio; AudioSource *micAudio;
List<AudioSource*> auxAudioSources; List<AudioSource*> auxAudioSources;
UINT sampleRateHz;
AudioEncoder *audioEncoder; AudioEncoder *audioEncoder;
//--------------------------------------------------- //---------------------------------------------------
@ -913,6 +915,8 @@ public:
OSLeaveMutex(hAuxAudioMutex); OSLeaveMutex(hAuxAudioMutex);
} }
inline UINT GetSampleRateHz() const {return sampleRateHz;}
inline QWORD GetAudioTime() const {return latestAudioTime;} inline QWORD GetAudioTime() const {return latestAudioTime;}
inline QWORD GetVideoTime() const {return latestVideoTime;} inline QWORD GetVideoTime() const {return latestVideoTime;}

View File

@ -284,7 +284,20 @@ retryHookTestV2:
} }
} }
//------------------------------------------------------------- //------------------------------------------------------------------
UINT format = AppConfig->GetInt(L"Audio Encoding", L"Format", 1);
switch (format) {
case 0: sampleRateHz = 44100; break;
default:
case 1: sampleRateHz = 48000; break;
}
Log(L"------------------------------------------");
Log(L"Audio Format: %uhz", sampleRateHz);
//------------------------------------------------------------------
AudioDeviceList playbackDevices; AudioDeviceList playbackDevices;
GetAudioDevices(playbackDevices, ADT_PLAYBACK); GetAudioDevices(playbackDevices, ADT_PLAYBACK);
@ -881,11 +894,11 @@ void OBS::EncodeAudioSegment(float *buffer, UINT numFrames, QWORD timestamp)
} }
} }
const int audioSamplesPerSec = 48000;
const int audioSampleSize = audioSamplesPerSec/100;
void OBS::MainAudioLoop() void OBS::MainAudioLoop()
{ {
const unsigned int audioSamplesPerSec = App->GetSampleRateHz();
const unsigned int audioSampleSize = audioSamplesPerSec/100;
DWORD taskID = 0; DWORD taskID = 0;
HANDLE hTask = AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskID); HANDLE hTask = AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskID);

View File

@ -265,7 +265,7 @@ char* OBS::EncMetaData(char *enc, char *pend, bool bFLVFile)
enc = AMF_EncodeNamedString(enc, pend, &av_audiocodecid, av_codecFourCC);//audioCodecID);// enc = AMF_EncodeNamedString(enc, pend, &av_audiocodecid, av_codecFourCC);//audioCodecID);//
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiodatarate, double(audioBitRate)); //ex. 128kb\s enc = AMF_EncodeNamedNumber(enc, pend, &av_audiodatarate, double(audioBitRate)); //ex. 128kb\s
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplerate, 48000.0); enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplerate, double(App->GetSampleRateHz()));
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplesize, 16.0); enc = AMF_EncodeNamedNumber(enc, pend, &av_audiosamplesize, 16.0);
enc = AMF_EncodeNamedNumber(enc, pend, &av_audiochannels, 2.0); enc = AMF_EncodeNamedNumber(enc, pend, &av_audiochannels, 2.0);
enc = AMF_EncodeNamedBoolean(enc, pend, &av_stereo, true); enc = AMF_EncodeNamedBoolean(enc, pend, &av_stereo, true);

View File

@ -213,7 +213,8 @@ INT_PTR SettingsEncoding::ProcMessage(UINT message, WPARAM wParam, LPARAM lParam
//-------------------------------------------- //--------------------------------------------
hwndTemp = GetDlgItem(hwnd, IDC_AUDIOFORMAT); hwndTemp = GetDlgItem(hwnd, IDC_AUDIOFORMAT);
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("48khz mono")); //SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("48khz mono"));
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("44.1khz stereo"));
SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("48khz stereo")); SendMessage(hwndTemp, CB_ADDSTRING, 0, (LPARAM)TEXT("48khz stereo"));
LoadSettingComboInt(hwndTemp, TEXT("Audio Encoding"), TEXT("Format"), 1, 1); LoadSettingComboInt(hwndTemp, TEXT("Audio Encoding"), TEXT("Format"), 1, 1);