From ef217eb0c2450e50a25e6ae2aee36178fcdd54c7 Mon Sep 17 00:00:00 2001 From: Tim Redfern Date: Wed, 3 Apr 2013 17:59:16 +0100 Subject: nearly got audio? --- rotord/1wave.mp3 | Bin 0 -> 8575 bytes rotord/1wave.wav | Bin 0 -> 88878 bytes rotord/rotor.cpp | 274 ++++++++--------------------------------------------- rotord/rotor.h | 8 +- rotord/silence.mp3 | Bin 481070 -> 8575 bytes rotord/silence.wav | Bin 2646044 -> 88244 bytes 6 files changed, 42 insertions(+), 240 deletions(-) create mode 100644 rotord/1wave.mp3 create mode 100644 rotord/1wave.wav diff --git a/rotord/1wave.mp3 b/rotord/1wave.mp3 new file mode 100644 index 0000000..040b65e Binary files /dev/null and b/rotord/1wave.mp3 differ diff --git a/rotord/1wave.wav b/rotord/1wave.wav new file mode 100644 index 0000000..0ae9d9b Binary files /dev/null and b/rotord/1wave.wav differ diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index 53ba33b..f7c017d 100644 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -10,14 +10,6 @@ bool fequal(const float u,const float v){ using namespace Rotor; -/* - string soname="qm-vamp-plugins"; - string id="qm-tempotracker"; - string myname=""; - string output=""; - int outputNo=0; - */ - void Render_context::runTask() { while (!isCancelled()) { int cmd=0; @@ -29,13 +21,10 @@ void Render_context::runTask() { mutex.unlock(); if (cmd==ANALYSE_AUDIO) { state=ANALYSING_AUDIO; - //audio_analyser.process(audio_filename); - //vampHost::runPlugin("","qm-vamp-plugins","qm-tempotracker", "",0, audio_filename, cerr,true); vector proc; proc.push_back(audio_thumb); if (load_audio(audio_filename,proc)) { state=AUDIO_READY; - //set the response } else state=IDLE; } @@ -72,8 +61,8 @@ bool Signal_output::render(const float duration, const float framerate,string &x } Command_response Render_context::session_command(const std::vector& command){ - //method,id,command1,{command2,}{body} - //here we allow the controlling server to communicate with running tasks + //method,id,command1,{command2,}{body} + //here we allow the controlling server to communicate with running tasks Command_response response; response.status=HTTPResponse::HTTP_BAD_REQUEST; if (command[2]=="audio") { @@ -82,9 +71,6 @@ Command_response Render_context::session_command(const std::vector& if (state==IDLE) { //check file exists Poco::File f=Poco::File(command[3]); - //std::auto_ptr pStr(URIStreamOpener::defaultOpener().open(command[3])); - - if (f.exists()) { //pass to worker thread ??if engine is ready?? ??what if engine has finished but results aren't read?? audio_filename=command[3]; //for now, store session variables in memory @@ -269,193 +255,8 @@ Command_response Render_context::session_command(const std::vector& //great to use c++11 features bool Render_context::load_audio(const string &filename,vector processors){ - //load audio data from file - //what's the best way to use this? the model is background processing, and we want to update a progress bar - //could pass a function pointer to call when each chunk of data becomes available? - //should the data processing be the responsibility of an object or a function? - //in the case of the audio thumbnail, there will be just one place where its kept - //in the case of audio analysis, the daemon will pass each audio analysis object each chunk of data as it gets it - //there could even be an array of audio analysis functions to perform simultaneously? - //how about a vector of objects that subclass the base audio processor class? - - //1st get parameters and initialise the processors - //then begin data loop locking progress variable after each frame - - // - // - //the example in ffmpeg works, but it isn't one that identifies a codec- it is hard coded to look for a codec for AV_CODEC_ID_MP2 - //it also doesn't load through libavformat - which opens containers- it just loads a naked .mp2 stream - // - // - - /* - av_register_all(); - - std::shared_ptr avFormat(avformat_alloc_context(), &avformat_free_context); - - auto avFormatPtr = avFormat.get(); - if (avformat_open_input(&avFormatPtr,filename.c_str(),nullptr, nullptr) != 0) { - cerr <<"Rotor: Error while calling avformat_open_input (probably invalid file format)" << endl; - return false; - } - - if (avformat_find_stream_info(avFormat.get(), nullptr) < 0) { - cerr << "Rotor: Error while calling avformat_find_stream_info" << endl; - return false; - } - - av_dump_format(avFormat.get(), 0, 0, false); //avformat.h line 1256 - - - - AVStream* stream = nullptr; - for (unsigned int i = 0; i < avFormat->nb_streams; ++i) { - if (avFormat->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - // we've found a stream! - stream = avFormat->streams[i]; - break; - } - } - if (!stream) { - cerr <<"Rotor: Didn't find any audio stream in the file"<< endl; - return false; - } - - // getting the required codec structure - const auto codec = avcodec_find_decoder(stream->codec->codec_id); //returns AVCodec* - if (codec == nullptr) { - cerr <<"Rotor: Audio codec not available"<< endl; - return false; - } - - //AVCodecContext?? avFormat->streams[i]->codec - - // allocating a structure - std::shared_ptr audioCodec(avcodec_alloc_context3(codec), [](AVCodecContext* c) { avcodec_close(c); av_free(c); }); - - // extradata??? - // we need to make a copy of videoStream->codec->extradata and give it to the context - // make sure that this vector exists as long as the avVideoCodec exists - std::vector codecContextExtraData; - codecContextExtraData.assign(stream->codec->extradata, stream->codec->extradata + stream->codec->extradata_size); - - audioCodec->extradata = reinterpret_cast(codecContextExtraData.data()); - audioCodec->extradata_size = codecContextExtraData.size(); - - // initializing the structure by opening the codec - if (avcodec_open2(audioCodec.get(), codec, nullptr) < 0) { - cerr <<"Rotor: Could not open codec"<< endl; - return false; - } - - - //avcodec.h line 1026 - - - Packet packet; - -// decoding code here - //cerr << "audio codec context - sample rate: "<< audioCodec->sample_rate <<", channels: "<channels<<", sample format: "<sample_fmt<index) - /// continue; // the packet is not about the stream we want, let's jump again the start of the loop - //} while(0); - // - - // allocating an AVFrame - std::shared_ptr avFrame(avcodec_alloc_frame(), &av_free); - - // the current packet of data - //Packet packet; - // data in the packet of data already processed - size_t offsetInData = 0; - - - bool foundPacket=false; - - // the decoding loop, running until EOF - while (true) { - // reading a packet using libavformat - if (offsetInData >= packet.packet.size) { - do { - packet.reset(avFormat.get()); - if (packet.packet.stream_index != stream->index) - continue; - } while(0); - if (!foundPacket){ - cerr << "audio codec context - sample rate: "<< audioCodec->sample_rate <<", channels: "<channels<<", sample format: "<sample_fmt<sample_fmt) * CHAR_BIT; // 16 or 32 - //unsigned int numberOfChannels = stream.codecContext->channels; // 1 for mono, 2 for stereo, or more - //unsigned int numberOfSamplesContainedInTheFrame = stream.frame->nb_samples * stream.codecContext->channels; - //unsigned int numberOfSamplesToPlayPerSecond = stream.codecContext->sample_rate; // usually 44100 or 48000 - //const void* data = stream.frame->data[0]; - - - if (processedLength < 0) { - //av_free_packet(&packet); shouldn't have to because of type safe wrapper - cerr <<"Error "<ticks_per_frame * 1000 * avVideoContext->time_base.num / avVideoContext->time_base.den; - std::this_thread::sleep(std::chrono::milliseconds(msToWait)); - } - */ - - - //http://www.gamedev.net/topic/624876-how-to-read-an-audio-file-with-ffmpeg-in-c/ - // Initialize FFmpeg - - //this seems to only read a certain percentage of the sound file? - different for wav and mp3 - //peculiar, because the data comes in as frames and we just read them until all are done - //is it possible that thhe problem lies with the drawing process only? - //wav sees 6/10 waves and mp3 sees 3.5/10 - //could this be an aliasing effect i.e. from reading the sample format wrong? - //I think probably not? - - //every format combination seems to miss a different number of samples - //I don't understand how different formats would make the samples seem to truncate? - //unless its an aliasing type thing? - - //wave.mp3 reads 16.409% of 160913 - //wave.wav reads 29.706% of 882044 - - - - av_register_all(); - //?? - //avcodec_init(); - avcodec_register_all(); - //?? + av_register_all(); AVFrame* frame = avcodec_alloc_frame(); if (!frame) @@ -464,8 +265,6 @@ bool Render_context::load_audio(const string &filename,vectornb_streams; ++i) { if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) @@ -519,12 +317,6 @@ bool Render_context::load_audio(const string &filename,vectorcodec->capabilities & CODEC_CAP_TRUNCATED) codecContext->codec->capabilities|=CODEC_FLAG_TRUNCATED; - // - // av_dump_format(formatContext, 0, 0, false); //avformat.h line 1256 int samples = ((formatContext->duration + 5000)*codecContext->sample_rate)/AV_TIME_BASE; @@ -532,9 +324,6 @@ bool Render_context::load_audio(const string &filename,vectorchannels << " channels, a sample rate of " << codecContext->sample_rate << "Hz and "<sample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<init(codecContext->channels,16,samples); } @@ -545,16 +334,13 @@ bool Render_context::load_audio(const string &filename,vectorindex) { // Try to decode the packet into a frame @@ -580,7 +366,6 @@ bool Render_context::load_audio(const string &filename,vectornb_samples<<" samples"<process_frame(frame->data[0],frame->nb_samples); @@ -592,7 +377,7 @@ bool Render_context::load_audio(const string &filename,vectoroffset) this_val=-(this_val-(offset*2)); - double val=((double)this_val)*scale; - accum+=abs(val); //(val*val); + + // + //cerr << this_val << " "; + // + + + //if (this_val>offset) this_val=-(this_val-(offset*2)); + + //this_val -=offset; + double val=((double)((int16_t)this_val))*scale; + accum+=val*val; samples++; } in_sample++; sample++; out_sample++; } - //get root-mean - double mean=accum/samples; //pow(accum/samples,0.5); - int colheight=height*mean*0.5; - int hh=height>>1; - for (int i=0;i>1; + for (int i=0;i