| 
							- /*
 -  * Carla Native Plugins
 -  * Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of
 -  * the License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 -  * GNU General Public License for more details.
 -  *
 -  * For a full copy of the GNU General Public License see the GPL.txt file
 -  */
 - 
 - #include "CarlaNative.h"
 - 
 - #include "audio_decoder/ad.h"
 - 
 - #include <pthread.h>
 - #include <stdlib.h>
 - #include <stdio.h>
 - #include <unistd.h>
 - 
 - typedef struct adinfo   ADInfo;
 - typedef pthread_mutex_t Mutex;
 - typedef pthread_t       Thread;
 - 
 - typedef struct _AudioFilePool {
 -     float* buffer[2];
 -     uint32_t startFrame;
 -     uint32_t size;
 - 
 - } AudioFilePool;
 - 
 - typedef struct _AudioFileInstance {
 -     HostDescriptor* host;
 - 
 -     void*  filePtr;
 -     ADInfo fileNfo;
 - 
 -     uint32_t lastFrame;
 -     uint32_t maxFrame;
 -     AudioFilePool pool;
 - 
 -     bool needsRead;
 -     bool doProcess;
 -     bool doQuit;
 - 
 -     Mutex  mutex;
 -     Thread thread;
 - 
 - } AudioFileInstance;
 - 
 - // ------------------------------------------------------------------------------------------
 - 
 - static bool gADInitiated = false;
 - 
 - // ------------------------------------------------------------------------------------------
 - 
 - void zeroFloat(float* data, unsigned size)
 - {
 -     for (unsigned i=0; i < size; ++i)
 -         *data++ = 0.0f;
 - }
 - 
 - void audiofile_read_poll(AudioFileInstance* const handlePtr)
 - {
 -     if (handlePtr->fileNfo.frames == 0)
 -     {
 -         //fprintf(stderr, "R: no song loaded\n");
 -         handlePtr->needsRead = false;
 -         return;
 -     }
 - 
 -     int64_t lastFrame = handlePtr->lastFrame;
 - 
 -     if (lastFrame >= handlePtr->maxFrame)
 -     {
 -         //fprintf(stderr, "R: transport out of bounds\n");
 -         handlePtr->needsRead = false;
 -         return;
 -     }
 - 
 -     // temp data buffer
 -     const uint32_t tmpSize = handlePtr->pool.size * handlePtr->fileNfo.channels;
 - 
 -     float tmpData[tmpSize];
 -     zeroFloat(tmpData, tmpSize);
 - 
 -     {
 -         fprintf(stderr, "R: poll data - reading at %li:%02li\n", lastFrame/44100/60, (lastFrame/44100) % 60);
 - 
 -         ad_seek(handlePtr->filePtr, lastFrame);
 -         ssize_t i, j, rv = ad_read(handlePtr->filePtr, tmpData, tmpSize);
 - 
 -         {
 -             // lock, and put data asap
 -             pthread_mutex_lock(&handlePtr->mutex);
 - 
 -             //zeroFloat(handlePtr->pool.buffer[0], handlePtr->pool.size);
 -             //zeroFloat(handlePtr->pool.buffer[1], handlePtr->pool.size);
 - 
 -             for (i=0, j=0; i < handlePtr->pool.size && j < rv; j++)
 -             {
 -                 if (handlePtr->fileNfo.channels == 1)
 -                 {
 -                     handlePtr->pool.buffer[0][i] = tmpData[j];
 -                     handlePtr->pool.buffer[1][i] = tmpData[j];
 -                     i++;
 -                 }
 -                 else
 -                 {
 -                     if (j % 2 == 0)
 -                     {
 -                         handlePtr->pool.buffer[0][i] = tmpData[j];
 -                     }
 -                     else
 -                     {
 -                         handlePtr->pool.buffer[1][i] = tmpData[j];
 -                         i++;
 -                     }
 -                 }
 -             }
 - 
 -             for (; i < handlePtr->pool.size; i++)
 -             {
 -                 handlePtr->pool.buffer[0][i] = 0.0f;
 -                 handlePtr->pool.buffer[1][i] = 0.0f;
 -             }
 - 
 -             handlePtr->pool.startFrame = lastFrame;
 - 
 -             // done
 -             pthread_mutex_unlock(&handlePtr->mutex);
 -         }
 -     }
 - 
 -     handlePtr->needsRead = false;
 - }
 - 
 - void audiofile_load_filename(AudioFileInstance* const handlePtr, const char* const filename)
 - {
 -     // wait for jack processing to end
 -     handlePtr->doProcess = false;
 -     pthread_mutex_lock(&handlePtr->mutex);
 -     pthread_mutex_unlock(&handlePtr->mutex);
 - 
 -     // clear old data
 -     if (handlePtr->filePtr != NULL)
 -     {
 -         ad_close(handlePtr->filePtr);
 -         handlePtr->filePtr = NULL;
 -     }
 -     ad_clear_nfo(&handlePtr->fileNfo);
 - 
 -     // open new
 -     handlePtr->filePtr = ad_open(filename, &handlePtr->fileNfo);
 - 
 -     if (handlePtr->filePtr != NULL)
 -     {
 -         ad_dump_nfo(1, &handlePtr->fileNfo);
 - 
 -         if (handlePtr->fileNfo.channels == 1 || handlePtr->fileNfo.channels == 2)
 -         {
 -             handlePtr->maxFrame = handlePtr->fileNfo.frames;
 -             audiofile_read_poll(handlePtr);
 -             handlePtr->doProcess = true;
 -         }
 -         else
 -         {
 -             ad_close(handlePtr->filePtr);
 -             handlePtr->filePtr = NULL;
 -             ad_clear_nfo(&handlePtr->fileNfo);
 -         }
 -     }
 - }
 - 
 - static void audiofile_thread_idle(void* ptr)
 - {
 -     AudioFileInstance* const handlePtr = (AudioFileInstance*)ptr;
 - 
 -     while (! handlePtr->doQuit)
 -     {
 -         if (handlePtr->needsRead || handlePtr->lastFrame - handlePtr->pool.startFrame >= handlePtr->pool.size*3/4)
 -             audiofile_read_poll(handlePtr);
 -         else
 -             usleep(50*1000);
 -     }
 - 
 -     pthread_exit(0);
 - }
 - 
 - // ------------------------------------------------------------------------------------------
 - 
 - static PluginHandle audiofile_instantiate(const PluginDescriptor* _this_, HostDescriptor* host)
 - {
 -     AudioFileInstance* const handlePtr = (AudioFileInstance*)malloc(sizeof(AudioFileInstance));
 - 
 -     if (handlePtr == NULL)
 -         return NULL;
 - 
 -     if (! gADInitiated)
 -     {
 -         ad_init();
 -         gADInitiated = true;
 -     }
 - 
 -     // init
 -     handlePtr->host = host;
 -     handlePtr->filePtr   = NULL;
 -     handlePtr->lastFrame = 0;
 -     handlePtr->maxFrame  = 0;
 -     handlePtr->pool.buffer[0]  = NULL;
 -     handlePtr->pool.buffer[1]  = NULL;
 -     handlePtr->pool.startFrame = 0;
 -     handlePtr->pool.size = 0;
 - 
 -     handlePtr->needsRead = false;
 -     handlePtr->doProcess = false;
 -     handlePtr->doQuit    = false;
 - 
 -     ad_clear_nfo(&handlePtr->fileNfo);
 -     pthread_mutex_init(&handlePtr->mutex, NULL);
 - 
 -     // create audio pool
 -     handlePtr->pool.size  = host->get_sample_rate(host->handle) * 6; // 6 secs
 - 
 -     handlePtr->pool.buffer[0] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
 -     handlePtr->pool.buffer[1] = (float*)malloc(sizeof(float) * handlePtr->pool.size);
 - 
 -     if (handlePtr->pool.buffer[0] == NULL || handlePtr->pool.buffer[1] == NULL)
 -     {
 -         free(handlePtr);
 -         return NULL;
 -     }
 - 
 -     zeroFloat(handlePtr->pool.buffer[0], handlePtr->pool.size);
 -     zeroFloat(handlePtr->pool.buffer[1], handlePtr->pool.size);
 - 
 -     pthread_create(&handlePtr->thread, NULL, (void*)&audiofile_thread_idle, handlePtr);
 - 
 -     // load file, TESTING
 -     // wait for jack processing to end
 -     handlePtr->doProcess = false;
 -     pthread_mutex_lock(&handlePtr->mutex);
 -     pthread_mutex_unlock(&handlePtr->mutex);
 - 
 -     return handlePtr;
 - 
 -     // unused
 -     (void)_this_;
 - }
 - 
 - static void audiofile_cleanup(PluginHandle handle)
 - {
 -     AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
 - 
 -     // wait for processing to end
 -     handlePtr->doProcess = false;
 -     handlePtr->doQuit    = true;
 -     pthread_mutex_lock(&handlePtr->mutex);
 - 
 -     pthread_join(handlePtr->thread, NULL);
 -     pthread_mutex_unlock(&handlePtr->mutex);
 -     pthread_mutex_destroy(&handlePtr->mutex);
 - 
 -     if (handlePtr->filePtr != NULL)
 -         ad_close(handlePtr->filePtr);
 - 
 -     if (handlePtr->pool.buffer[0] != NULL)
 -         free(handlePtr->pool.buffer[0]);
 - 
 -     if (handlePtr->pool.buffer[1] != NULL)
 -         free(handlePtr->pool.buffer[1]);
 - 
 -     free(handlePtr);
 - }
 - 
 - static void audiofile_set_custom_data(PluginHandle handle, const char* key, const char* value)
 - {
 -     AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
 - 
 -     if (strcmp(key, "file") == 0)
 -         audiofile_load_filename(handlePtr, value);
 - }
 - 
 - static void audiofile_process(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents)
 - {
 -     AudioFileInstance* const handlePtr = (AudioFileInstance*)handle;
 - 
 -     float* out1 = outBuffer[0];
 -     float* out2 = outBuffer[1];
 - 
 -     if (! handlePtr->doProcess)
 -     {
 -         //fprintf(stderr, "P: no process\n");
 -         zeroFloat(out1, frames);
 -         zeroFloat(out2, frames);
 -         return;
 -     }
 - 
 -     const TimeInfo* const timePos = handlePtr->host->get_time_info(handlePtr->host->handle);
 - 
 -     // not playing
 -     if (! timePos->playing)
 -     {
 -         //fprintf(stderr, "P: not rolling\n");
 -         handlePtr->lastFrame = timePos->frame;
 - 
 -         zeroFloat(out1, frames);
 -         zeroFloat(out2, frames);
 -         return;
 -     }
 - 
 -     pthread_mutex_lock(&handlePtr->mutex);
 - 
 -     // out of reach
 -     if (timePos->frame + frames < handlePtr->pool.startFrame || timePos->frame >= handlePtr->maxFrame)
 -     {
 -         //fprintf(stderr, "P: non-continuous playback, out of reach %u vs %u\n", timePos->frame + frames, handlePtr->maxFrame);
 -         handlePtr->lastFrame = timePos->frame;
 -         handlePtr->needsRead = true;
 -         pthread_mutex_unlock(&handlePtr->mutex);
 - 
 -         zeroFloat(out1, frames);
 -         zeroFloat(out2, frames);
 -         return;
 -     }
 - 
 -     int64_t poolFrame = (int64_t)timePos->frame - handlePtr->pool.startFrame;
 -     int64_t poolSize  = handlePtr->pool.size;
 - 
 -     for (uint32_t i=0; i < frames; i++, poolFrame++)
 -     {
 -         if (poolFrame >= 0 && poolFrame < poolSize)
 -         {
 -             out1[i] = handlePtr->pool.buffer[0][poolFrame];
 -             out2[i] = handlePtr->pool.buffer[1][poolFrame];
 - 
 -             // reset
 -             handlePtr->pool.buffer[0][poolFrame] = 0.0f;
 -             handlePtr->pool.buffer[1][poolFrame] = 0.0f;
 -         }
 -         else
 -         {
 -             out1[i] = 0.0f;
 -             out2[i] = 0.0f;
 -         }
 -     }
 - 
 -     handlePtr->lastFrame = timePos->frame;
 -     pthread_mutex_unlock(&handlePtr->mutex);
 - 
 -     return;
 - 
 -     // unused
 -     (void)inBuffer;
 -     (void)midiEventCount;
 -     (void)midiEvents;
 - }
 - 
 - // -----------------------------------------------------------------------
 - 
 - static const PluginDescriptor audiofileDesc = {
 -     .category  = PLUGIN_CATEGORY_UTILITY,
 -     .hints     = PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI,
 -     .audioIns  = 0,
 -     .audioOuts = 2,
 -     .midiIns   = 0,
 -     .midiOuts  = 0,
 -     .parameterIns  = 0,
 -     .parameterOuts = 0,
 -     .name      = "Audio File",
 -     .label     = "audiofile",
 -     .maker     = "falkTX",
 -     .copyright = "GNU GPL v2+",
 - 
 -     .instantiate = audiofile_instantiate,
 -     .cleanup     = audiofile_cleanup,
 - 
 -     .get_parameter_count = NULL,
 -     .get_parameter_info  = NULL,
 -     .get_parameter_value = NULL,
 -     .get_parameter_text  = NULL,
 - 
 -     .get_midi_program_count = NULL,
 -     .get_midi_program_info  = NULL,
 - 
 -     .set_parameter_value = NULL,
 -     .set_midi_program    = NULL,
 -     .set_custom_data     = audiofile_set_custom_data,
 - 
 -     .ui_show = NULL,
 -     .ui_idle = NULL,
 - 
 -     .ui_set_parameter_value = NULL,
 -     .ui_set_midi_program    = NULL,
 -     .ui_set_custom_data     = NULL,
 - 
 -     .activate   = NULL,
 -     .deactivate = NULL,
 -     .process    = audiofile_process
 - };
 - 
 - // -----------------------------------------------------------------------
 - 
 - void carla_register_native_plugin_audiofile()
 - {
 -     carla_register_native_plugin(&audiofileDesc);
 - }
 - 
 - // -----------------------------------------------------------------------
 - // amagamated build
 - 
 - #include "audio_decoder/ad_ffmpeg.c"
 - #include "audio_decoder/ad_plugin.c"
 - #include "audio_decoder/ad_soundfile.c"
 - 
 - // -----------------------------------------------------------------------
 
 
  |