Last active
October 19, 2019 16:21
-
-
Save eruffaldi/86755065f4c777f01f972abf51890a6e to your computer and use it in GitHub Desktop.
PortAudio to MP3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://github.com/eruffaldi/cmakego | |
find_package(cmakego COMPONENTS portaudio lame) | |
add_executable(testpa testpa.cpp) | |
target_link_libraries(testpa p::portaudio p::lame) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NOTES: | |
// https://github.com/EddieRingle/portaudio/blob/master/src/common/pa_converters.c | |
// http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html#a6fea69f3d81b628288325c06310b2fcf | |
// | |
#include "portaudio.h" | |
#include <iostream> | |
#include <vector> | |
#include <fstream> | |
#include "lame/lame.h" | |
struct Mp3encoder | |
{ | |
Mp3encoder(int samplerate, int channels, int bitrate, std::string name); | |
~Mp3encoder(); | |
void encode_inter(const short * s, int samples); | |
void encode_sep(const int32_t * L, const int32_t *R, int samples); | |
void encode_sep(const int16_t * L, const int16_t *R, int samples); | |
void flush(); | |
std::vector<char> buf; | |
std::ofstream onf; | |
lame_global_flags *p; | |
}; | |
Mp3encoder::Mp3encoder(int samplerate, int channels, int bitrate, std::string name): onf(name.c_str(),std::ios::binary) | |
{ | |
buf.resize(1024*64); | |
p = lame_init(); | |
if(!p) | |
{ | |
std::cout << "bad p " << std::endl; | |
exit(0); | |
} | |
lame_set_in_samplerate(p,samplerate); // default is 44100 | |
lame_set_num_channels(p,channels); | |
lame_set_out_samplerate(p,0); // automatic | |
/* | |
internal algorithm selection. True quality is determined by the bitrate | |
but this variable will effect quality by selecting expensive or cheap algorithms. | |
quality=0..9. 0=best (very slow). 9=worst. | |
recommended: 2 near-best quality, not too slow | |
5 good quality, fast | |
7 ok quality, really fast | |
*/ | |
//lame_set_quality(p,...) | |
lame_set_brate(p,bitrate); | |
lame_init_params(p); | |
} | |
void Mp3encoder::encode_inter(const short * s, int samples) | |
{ | |
int n = lame_encode_buffer_interleaved(p,(short int*)s,samples,(unsigned char*)&buf[0],buf.size()); | |
onf.write(&buf[0],n); | |
} | |
void Mp3encoder::encode_sep(const int32_t * L,const int32_t * R, int samples) | |
{ | |
int n = lame_encode_buffer_int(p,(int32_t*)L,(int32_t*)R,samples,(unsigned char*)&buf[0],buf.size()); | |
onf.write(&buf[0],n); | |
} | |
void Mp3encoder::encode_sep(const int16_t * L,const int16_t * R, int samples) | |
{ | |
int n = lame_encode_buffer(p,(int16_t*)L,(int16_t*)R,samples,(unsigned char*)&buf[0],buf.size()); | |
onf.write(&buf[0],n); | |
} | |
void Mp3encoder::flush() | |
{ | |
int n = lame_encode_flush(p,(unsigned char*)&buf[0],buf.size()); | |
onf.write(&buf[0],n); | |
} | |
Mp3encoder::~Mp3encoder() | |
{ | |
lame_close(p); | |
} | |
int portAudioCallback_int(const void * input, void * output, | |
unsigned long frameCount, const PaStreamCallbackTimeInfo * timeInfo, | |
PaStreamCallbackFlags statusFlags, void * userData){ | |
Mp3encoder * enc = (Mp3encoder*)userData; | |
enc->encode_inter((short*)input,frameCount); | |
return 0; | |
} | |
int portAudioCallback_i32(const void * input, void * output, | |
unsigned long frameCount, const PaStreamCallbackTimeInfo * timeInfo, | |
PaStreamCallbackFlags statusFlags, void * userData){ | |
Mp3encoder * enc = (Mp3encoder*)userData; | |
const int32_t ** pc = (const int32_t**)input; | |
enc->encode_sep(pc[0],pc[1],frameCount); | |
return 0; | |
} | |
int portAudioCallback_i16(const void * input, void * output, | |
unsigned long frameCount, const PaStreamCallbackTimeInfo * timeInfo, | |
PaStreamCallbackFlags statusFlags, void * userData){ | |
Mp3encoder * enc = (Mp3encoder*)userData; | |
const int16_t ** pc = (const int16_t**)input; | |
enc->encode_sep(pc[0],pc[1],frameCount); | |
return 0; | |
} | |
int main(int argc, char const *argv[]) | |
{ | |
static_assert(sizeof(int) == 4,"lame support 32"); | |
const char * whichname = argc == 1 ? "Built-in Microph": argv[1]; | |
Pa_Initialize(); | |
int used_device = -1; | |
for(int i = 0; i < Pa_GetDeviceCount(); ++i){ | |
//std::cout << Pa_GetDeviceInfo(i)->name << std::endl; | |
if(std::string(Pa_GetDeviceInfo(i)->name).find(whichname) != std::string::npos) | |
{ | |
used_device = i; | |
break; | |
} | |
std::cout << "skipped " << Pa_GetDeviceInfo(i)->name << std::endl; | |
} | |
if(used_device == -1){ | |
std::cout << "device " << whichname << std::endl; | |
return 0; | |
} | |
std::cout << "Using device : " << Pa_GetDeviceInfo(used_device)->name << std::endl; | |
const double srate = Pa_GetDeviceInfo(used_device)->defaultSampleRate; | |
PaStream * stream; | |
unsigned long framesPerBuffer = paFramesPerBufferUnspecified; | |
//PaStreamParameters outputParameters; | |
PaStreamParameters inputParameters; | |
inputParameters.channelCount = Pa_GetDeviceInfo(used_device)->maxInputChannels; | |
inputParameters.device = used_device; | |
inputParameters.hostApiSpecificStreamInfo = NULL; | |
inputParameters.sampleFormat = paInt32|paNonInterleaved; // paFloat32; | |
inputParameters.suggestedLatency = Pa_GetDeviceInfo(used_device)->defaultLowInputLatency; | |
inputParameters.hostApiSpecificStreamInfo = NULL; | |
std::cout << "initing encoder with channels " << inputParameters.channelCount << " srate " << srate << std::endl; | |
Mp3encoder enc(srate,inputParameters.channelCount,128000,"ciao.mp3"); | |
std::cout << "done encoder " << std::endl; | |
if(Pa_OpenStream(&stream, &inputParameters, NULL, srate, framesPerBuffer, paNoFlag, portAudioCallback_i32, &enc) || Pa_StartStream(stream)){ | |
std::cout << "error opening stream. Audio won't be available" << std::endl; | |
} else{ | |
int q = 10; | |
while(q--) | |
{ | |
std::cout << " q " << q << std::endl; | |
Pa_Sleep(1000); | |
} | |
} | |
Pa_CloseStream(stream); | |
Pa_Terminate(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment