diff options
| -rw-r--r-- | rotord/Makefile | 2 | ||||
| -rw-r--r-- | rotord/rotor.cpp | 176 | ||||
| -rwxr-xr-x | rotord/rotor.h | 31 |
3 files changed, 187 insertions, 22 deletions
diff --git a/rotord/Makefile b/rotord/Makefile index 3ccbfc2..d153562 100644 --- a/rotord/Makefile +++ b/rotord/Makefile @@ -1,5 +1,5 @@ # The pre-processor and compiler options. -MY_CFLAGS = -fpermissive -std=c++11 +MY_CFLAGS = -fpermissive -std=c++11 -Wno-error # -I ../ffmpeg diff --git a/rotord/rotor.cpp b/rotord/rotor.cpp index b8c5e2f..de9f4ea 100644 --- a/rotord/rotor.cpp +++ b/rotord/rotor.cpp @@ -32,8 +32,10 @@ void Render_context::runTask() { //audio_analyser.process(audio_filename); //vampHost::runPlugin("","qm-vamp-plugins","qm-tempotracker", "",0, audio_filename, cerr,true); vector<base_audio_processor*> proc; + proc.push_back(new audio_thumbnailer()); if (load_audio(audio_filename,proc)) { state=AUDIO_READY; + //set the response } else state=IDLE; } @@ -290,6 +292,7 @@ bool Render_context::load_audio(const string &filename,vector<base_audio_process // // + /* av_register_all(); std::shared_ptr<AVFormatContext> avFormat(avformat_alloc_context(), &avformat_free_context); @@ -358,13 +361,12 @@ bool Render_context::load_audio(const string &filename,vector<base_audio_process // decoding code here //cerr << "audio codec context - sample rate: "<< audioCodec->sample_rate <<", channels: "<<audioCodec->channels<<", sample format: "<<audioCodec->sample_fmt<<endl; - /* suspect why was this in twice 210313 - do { - packet.reset(avFormat.get()); - if (packet.packet.stream_index != stream->index) - continue; // the packet is not about the stream we want, let's jump again the start of the loop - } while(0); - */ + // suspect why was this in twice 210313 + //do { + // if (packet.packet.stream_index != stream->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> avFrame(avcodec_alloc_frame(), &av_free); @@ -406,22 +408,22 @@ bool Render_context::load_audio(const string &filename,vector<base_audio_process const auto processedLength = avcodec_decode_audio4(audioCodec.get(), avFrame.get(), &isFrameAvailable, &packetToSend); //utils.c line 2018 -/* - unsigned int bitsPerSample = av_get_bytes_per_sample(stream.codecContext->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]; - */ + + //unsigned int bitsPerSample = av_get_bytes_per_sample(stream.codecContext->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 while processing the data"<< endl; + cerr <<"Error "<<processedLength<< " while processing the data"<< endl; return false; } offsetInData += processedLength; - /* + // processing the image if available if (isFrameAvailable) { // display image on the screen @@ -432,8 +434,150 @@ bool Render_context::load_audio(const string &filename,vector<base_audio_process } */ + + http://www.gamedev.net/topic/624876-how-to-read-an-audio-file-with-ffmpeg-in-c/ + // Initialize FFmpeg + av_register_all(); + + AVFrame* frame = avcodec_alloc_frame(); + if (!frame) + { + std::cout << "Error allocating the frame" << std::endl; + return false; + } + + // you can change the file name "01 Push Me to the Floor.wav" to whatever the file is you're reading, like "myFile.ogg" or + // "someFile.webm" and this should still work + AVFormatContext* formatContext = NULL; + if (avformat_open_input(&formatContext, filename.c_str(), NULL, NULL) != 0) + { + av_free(frame); + std::cout << "Error opening the file" << std::endl; + return false; + } + + + if (avformat_find_stream_info(formatContext, NULL) < 0) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Error finding the stream info" << std::endl; + return false; + } + + AVStream* audioStream = NULL; + // Find the audio stream (some container files can have multiple streams in them) + for (unsigned int i = 0; i < formatContext->nb_streams; ++i) + { + if (formatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + { + audioStream = formatContext->streams[i]; + break; + } } + if (audioStream == NULL) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Could not find any audio stream in the file" << std::endl; + return false; + } + + AVCodecContext* codecContext = audioStream->codec; + + codecContext->codec = avcodec_find_decoder(codecContext->codec_id); + if (codecContext->codec == NULL) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Couldn't find a proper decoder" << std::endl; + return false; + } + else if (avcodec_open2(codecContext, codecContext->codec, NULL) != 0) + { + av_free(frame); + av_close_input_file(formatContext); + std::cout << "Couldn't open the context with the decoder" << std::endl; + return false; + } + + av_dump_format(formatContext, 0, 0, false); //avformat.h line 1256 + int samples = ((formatContext->duration + 5000)*codecContext->sample_rate)/AV_TIME_BASE; + + std::cout << "This stream has " << codecContext->channels << " channels, a sample rate of " << codecContext->sample_rate << "Hz and "<<samples <<" samples" << std::endl; + std::cout << "The data is in format " <<codecContext->sample_fmt<< " (aka "<< av_get_sample_fmt_name(codecContext->sample_fmt) << ") "<<std::endl; + + //we can now tell the processors the format + //we can work out the number of samples at this point + + + + + for (auto p: processors) { + p->init(codecContext->channels,16,samples); + } + + AVPacket packet; + av_init_packet(&packet); + + // Read the packets in a loop + while (av_read_frame(formatContext, &packet) == 0) + { + if (packet.stream_index == audioStream->index) + { + // Try to decode the packet into a frame + int frameFinished = 0; + int bytes = avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet); + + // Some frames rely on multiple packets, so we have to make sure the frame is finished before + // we can use it + if (frameFinished) + { + // frame now has usable audio data in it. How it's stored in the frame depends on the format of + // the audio. If it's packed audio, all the data will be in frame->data[0]. If it's in planar format, + // the data will be in frame->data and possibly frame->extended_data. Look at frame->data, frame->nb_samples, + // frame->linesize, and other related fields on the FFmpeg docs. I don't know how you're actually using + // the audio data, so I won't add any junk here that might confuse you. Typically, if I want to find + // documentation on an FFmpeg structure or function, I just type "<name> doxygen" into google (like + // "AVFrame doxygen" for AVFrame's docs) + + //std::cout << "Got a frame: bytes " << bytes << std::endl; + //now we can pass the data to the processor(s) + for (auto p: processors) { + p->process_frame(frame->data[0],frame->nb_samples); + } + + } + } + + // You *must* call av_free_packet() after each call to av_read_frame() or else you'll leak memory + av_free_packet(&packet); + } + + // Some codecs will cause frames to be buffered up in the decoding process. If the CODEC_CAP_DELAY flag + // is set, there can be buffered up frames that need to be flushed, so we'll do that + if (codecContext->codec->capabilities & CODEC_CAP_DELAY) + { + av_init_packet(&packet); + // Decode all the remaining frames in the buffer, until the end is reached + int frameFinished = 0; + int bytes = avcodec_decode_audio4(codecContext, frame, &frameFinished, &packet); + while (bytes >= 0 && frameFinished) + { + for (auto p: processors) { + p->process_frame(frame->data[0],frame->nb_samples); + } + } + } + + // Clean up! + av_free(frame); + avcodec_close(codecContext); + av_close_input_file(formatContext); + + + return true; } diff --git a/rotord/rotor.h b/rotord/rotor.h index c08371d..132059f 100755 --- a/rotord/rotor.h +++ b/rotord/rotor.h @@ -335,17 +335,38 @@ namespace Rotor { }; class base_audio_processor { public: - base_audio_processor(); - base_audio_processor(int _channels,int _bits); - virtual bool process_chunk(char *data,int num_samples); - void init(int _channels,int _bits) { + virtual bool process_frame(uint8_t *data,int samples)=0; + void init(int _channels,int _bits,int _samples) { channels=_channels; bits=_bits; + samples=_samples; }; - int channels,bits; + int channels,bits,samples; }; class audio_thumbnailer: public base_audio_processor { + //how to deal with the fact that frames don't correspond with pixels? + //buffer the data somehow + //draw pixels based on rms value public: + audio_thumbnailer(){ + height=64; + width=512; + data=new uint8_t[height*width]; + memset(data,0,height*width); + } + ~audio_thumbnailer(){ + delete[] data; + } + void init(int _channels,int _bits,int _samples) { + base_audio_processor::init(_channels,_bits,_samples); + samples_per_column=samples/width(); + } + bool process_frame(uint8_t *data,int samples){ + + return true; + } + uint8_t *data; + int height,width,samples_per_column; }; class Render_context: public Poco::Task { //Poco task object //manages a 'patchbay' |
