|
@@ -0,0 +1,319 @@
|
|
|
+/*
|
|
|
+ * AudiToMidi.cpp
|
|
|
+ *
|
|
|
+ * Created on: 16 déc. 2023
|
|
|
+ * Author: fanch
|
|
|
+ */
|
|
|
+#define LSP_LIBRARY_EXTERN extern
|
|
|
+#include <cmath>
|
|
|
+#include <cstdlib>
|
|
|
+#include <cstdio>
|
|
|
+#include <cstring>
|
|
|
+
|
|
|
+#include "ladspa.h"
|
|
|
+
|
|
|
+#include <fftw3.h>
|
|
|
+#include <cstdint>
|
|
|
+#include <sched.h>
|
|
|
+#include <time.h>
|
|
|
+/* The port numbers for the plugin: */
|
|
|
+#include "SDLWindow.h"
|
|
|
+
|
|
|
+
|
|
|
+#define PLUGIN_COUNT 1
|
|
|
+#define PORT_COUNT 2
|
|
|
+#define INPUT_PORT 0
|
|
|
+#define OUTPUT_PORT 1
|
|
|
+#include <complex>
|
|
|
+typedef std::complex<float> Complex;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+class CustomFft {
|
|
|
+public:
|
|
|
+ CustomFft(float **input, float** output){
|
|
|
+ m_input = input;
|
|
|
+ m_output = output;
|
|
|
+ m_input_complex = NULL;
|
|
|
+ m_output_complex = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ void set_count(int n){
|
|
|
+ if(m_count == n) return;
|
|
|
+ if(m_input_complex) delete[] m_input_complex;
|
|
|
+ if(m_output_complex) delete[] m_output_complex;
|
|
|
+ m_count = n;
|
|
|
+ m_input_complex = new Complex[n];
|
|
|
+ m_output_complex = new Complex[n];
|
|
|
+ for(int i=0; i<n; i++){
|
|
|
+ m_input_complex[i].imag(0);
|
|
|
+ m_output_complex[i].imag(0);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ~CustomFft(){
|
|
|
+ if(m_input_complex) delete[] m_input_complex;
|
|
|
+ if(m_output_complex) delete[] m_output_complex;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ void execute(){
|
|
|
+ for(int i=0; i<m_count; i++){
|
|
|
+ m_input_complex[i].real(0);
|
|
|
+ }
|
|
|
+ for(int k = 0; k < m_count; k++)
|
|
|
+ {
|
|
|
+ Complex sum(0.0,0.0);
|
|
|
+ for(int j = 0; j < m_count; j++)
|
|
|
+ {
|
|
|
+ int integers = -2*j*k;
|
|
|
+ Complex my_exponent(0.0, M_PI/m_count*(double)integers);
|
|
|
+ sum += (*m_input)[j] * std::exp(my_exponent);
|
|
|
+ }
|
|
|
+
|
|
|
+ double val = abs(sum.real());
|
|
|
+ (*m_output)[k]=val;
|
|
|
+ }
|
|
|
+ (*m_output)[0]=0;
|
|
|
+ }
|
|
|
+
|
|
|
+protected:
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ float **m_input;
|
|
|
+ float **m_output;
|
|
|
+ Complex *m_input_complex;
|
|
|
+ Complex *m_output_complex;
|
|
|
+
|
|
|
+ long m_count;
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+uint64_t get_time_ns(){
|
|
|
+ struct timespec start;
|
|
|
+
|
|
|
+ if( clock_gettime( CLOCK_REALTIME, &start) == -1 ) {
|
|
|
+ perror( "clock gettime" );
|
|
|
+ exit( EXIT_FAILURE );
|
|
|
+ }
|
|
|
+ return start.tv_sec * 1000000000 + start.tv_nsec;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class AudiToMidi {
|
|
|
+public:
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ static LADSPA_Handle instanciate(const LADSPA_Descriptor *, unsigned long SampleRate){
|
|
|
+
|
|
|
+ return new AudiToMidi(SampleRate);
|
|
|
+ }
|
|
|
+
|
|
|
+ AudiToMidi(long sample_rate) : m_input_data(NULL), m_output_data(NULL), m_sample_rate(sample_rate) {
|
|
|
+ m_input_complex = fftw_alloc_complex(sample_rate);
|
|
|
+ m_output_complex = fftw_alloc_complex(sample_rate);
|
|
|
+ for(unsigned int i=0; i<sample_rate; i++){
|
|
|
+ m_output_complex[i][1] = m_input_complex[i][1] =0 ;
|
|
|
+ }
|
|
|
+ m_dftplan = fftw_plan_dft_1d(sample_rate, m_input_complex, m_output_complex, FFTW_FORWARD, FFTW_ESTIMATE);
|
|
|
+
|
|
|
+ count = 0;
|
|
|
+ m_fft = new CustomFft(&m_input_data, &m_output_data);
|
|
|
+ }
|
|
|
+
|
|
|
+ virtual ~AudiToMidi(){
|
|
|
+ fftw_destroy_plan(m_dftplan);
|
|
|
+ fftw_free(m_input_complex);
|
|
|
+ fftw_free(m_output_complex);
|
|
|
+ }
|
|
|
+
|
|
|
+ LADSPA_Data * m_input_data;
|
|
|
+ LADSPA_Data * m_output_data;
|
|
|
+ long m_sample_rate;
|
|
|
+ fftw_complex* m_input_complex;
|
|
|
+ fftw_complex* m_output_complex;
|
|
|
+ int count;
|
|
|
+ fftw_plan m_dftplan;
|
|
|
+ CustomFft* m_fft;
|
|
|
+ SDLWindow m_window;
|
|
|
+
|
|
|
+ void activate(){
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ void connect(unsigned long port, LADSPA_Data * data){
|
|
|
+ switch (port){
|
|
|
+ case INPUT_PORT: m_input_data = data; break;
|
|
|
+ case OUTPUT_PORT: m_output_data = data; break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ void run(long sc){
|
|
|
+
|
|
|
+ printf("RUN !!!!!!!\n");
|
|
|
+ m_fft->set_count(sc);
|
|
|
+
|
|
|
+ if(!m_input_data || !m_output_data) return;
|
|
|
+ uint64_t start, stop;
|
|
|
+ start = get_time_ns();
|
|
|
+ for(unsigned int i=0; i<sc; i++){
|
|
|
+ m_input_complex[i][0] = m_input_data[i] ;
|
|
|
+ }
|
|
|
+ fftw_execute(m_dftplan);
|
|
|
+ for(unsigned int i=0; i<sc; i++){
|
|
|
+ m_output_data[i] =isnan(m_output_complex[i][0])?0.0:m_output_complex[i][0] ;
|
|
|
+ }
|
|
|
+ m_window.set_value(NULL, sc);
|
|
|
+ //m_fft->execute();
|
|
|
+ count+=1;
|
|
|
+ stop = get_time_ns();
|
|
|
+ //m_window.set_value(m_output_data, sc);
|
|
|
+ printf("----- %d %d %lf ms\n", count, sc, ((double)(stop-start))/1000000);
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+static void activate_plugin(LADSPA_Handle Instance){
|
|
|
+ printf("activate_plugin\n");
|
|
|
+ ((AudiToMidi*)Instance)->activate();
|
|
|
+}
|
|
|
+
|
|
|
+static void connect_plugin(LADSPA_Handle Instance, unsigned long SampleCount, LADSPA_Data * data){
|
|
|
+ printf("connect_plugin\n");
|
|
|
+ return ((AudiToMidi*)Instance)->connect(SampleCount, data);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void run(LADSPA_Handle Instance, unsigned long SampleCount){
|
|
|
+ ((AudiToMidi*)Instance)->run(SampleCount);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void cleanup(LADSPA_Handle insatnce){
|
|
|
+ printf("cleanup\n");
|
|
|
+ delete (AudiToMidi *)insatnce;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+typedef char *char_ptr;
|
|
|
+
|
|
|
+static inline char *
|
|
|
+localStrdup(const char * input) {
|
|
|
+ char * output = new char[strlen(input) + 1];
|
|
|
+ strcpy(output, input);
|
|
|
+ return output;
|
|
|
+}
|
|
|
+
|
|
|
+static LADSPA_Descriptor *g_descriptors[1] = { NULL };
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+const LADSPA_Descriptor *
|
|
|
+ladspa_descriptor(unsigned long Index) {
|
|
|
+ if (Index < PLUGIN_COUNT){
|
|
|
+ return g_descriptors[Index];
|
|
|
+ }else
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* Global object used handle startup initialisation and shut down
|
|
|
+ tidying. Performs the function of the _init() and _fini() calls in
|
|
|
+ the C modules.*/
|
|
|
+class StartupShutdownHandler {
|
|
|
+public:
|
|
|
+
|
|
|
+ StartupShutdownHandler() {
|
|
|
+ SDLWindow::init();
|
|
|
+ struct sched_param sp = { .sched_priority = 50 };
|
|
|
+ //sched_setscheduler(0, SCHED_FIFO, &sp);
|
|
|
+
|
|
|
+ char **pcPortNames;
|
|
|
+ LADSPA_PortDescriptor *port_descriptors;
|
|
|
+ LADSPA_PortRangeHint *port_range_hints;
|
|
|
+
|
|
|
+ for (long plugin_index = 0; plugin_index < PLUGIN_COUNT; plugin_index++) {
|
|
|
+
|
|
|
+ g_descriptors[plugin_index] = new LADSPA_Descriptor;
|
|
|
+ if (g_descriptors[plugin_index] == NULL)
|
|
|
+ break;
|
|
|
+
|
|
|
+ g_descriptors[plugin_index]->UniqueID = 1078 + plugin_index;
|
|
|
+ g_descriptors[plugin_index]->Properties = LADSPA_PROPERTY_HARD_RT_CAPABLE;
|
|
|
+ g_descriptors[plugin_index]->Maker = localStrdup(
|
|
|
+ "François GAUTRAIS");
|
|
|
+ g_descriptors[plugin_index]->Copyright = localStrdup("None");
|
|
|
+ g_descriptors[plugin_index]->PortCount = PORT_COUNT;
|
|
|
+ port_descriptors = new LADSPA_PortDescriptor[PORT_COUNT];
|
|
|
+ g_descriptors[plugin_index]->PortDescriptors =
|
|
|
+ (const LADSPA_PortDescriptor*) port_descriptors;
|
|
|
+ port_descriptors[INPUT_PORT] = LADSPA_PORT_INPUT| LADSPA_PORT_AUDIO;
|
|
|
+ port_descriptors[OUTPUT_PORT] = LADSPA_PORT_OUTPUT| LADSPA_PORT_AUDIO;
|
|
|
+
|
|
|
+
|
|
|
+ pcPortNames = new char_ptr[PORT_COUNT];
|
|
|
+ g_descriptors[plugin_index]->PortNames = (const char**) pcPortNames;
|
|
|
+ pcPortNames[INPUT_PORT] = localStrdup("Entrée");
|
|
|
+ pcPortNames[OUTPUT_PORT] = localStrdup("Sortie");
|
|
|
+
|
|
|
+ port_range_hints = new LADSPA_PortRangeHint[PORT_COUNT];
|
|
|
+ g_descriptors[plugin_index]->PortRangeHints =
|
|
|
+ (const LADSPA_PortRangeHint*) port_range_hints;
|
|
|
+
|
|
|
+
|
|
|
+ port_range_hints[INPUT_PORT].HintDescriptor = 0;
|
|
|
+ port_range_hints[OUTPUT_PORT].HintDescriptor = 0;
|
|
|
+
|
|
|
+ g_descriptors[plugin_index]->instantiate = AudiToMidi::instanciate;
|
|
|
+ g_descriptors[plugin_index]->connect_port = connect_plugin;
|
|
|
+ g_descriptors[plugin_index]->activate = activate_plugin;
|
|
|
+ g_descriptors[plugin_index]->run_adding = NULL;
|
|
|
+ g_descriptors[plugin_index]->set_run_adding_gain = NULL;
|
|
|
+ g_descriptors[plugin_index]->deactivate = NULL;
|
|
|
+ g_descriptors[plugin_index]->cleanup = cleanup;
|
|
|
+
|
|
|
+ switch (plugin_index) {
|
|
|
+ case 0:
|
|
|
+ g_descriptors[plugin_index]->Label = localStrdup("audio_to_midi");
|
|
|
+ g_descriptors[plugin_index]->Name = localStrdup("Audio to midi");
|
|
|
+ g_descriptors[plugin_index]->run = run;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void deleteDescriptor(LADSPA_Descriptor *psDescriptor) {
|
|
|
+ unsigned long lIndex;
|
|
|
+ if (psDescriptor) {
|
|
|
+ delete[] psDescriptor->Label;
|
|
|
+ delete[] psDescriptor->Name;
|
|
|
+ delete[] psDescriptor->Maker;
|
|
|
+ delete[] psDescriptor->Copyright;
|
|
|
+ delete[] psDescriptor->PortDescriptors;
|
|
|
+ for (lIndex = 0; lIndex < psDescriptor->PortCount; lIndex++)
|
|
|
+ delete[] psDescriptor->PortNames[lIndex];
|
|
|
+ delete[] psDescriptor->PortNames;
|
|
|
+ delete[] psDescriptor->PortRangeHints;
|
|
|
+ delete psDescriptor;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ~StartupShutdownHandler() {
|
|
|
+
|
|
|
+ for (long plugin_index = 0; plugin_index < PLUGIN_COUNT; plugin_index++) {
|
|
|
+ deleteDescriptor(g_descriptors[plugin_index]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static StartupShutdownHandler g_oShutdownStartupHandler;
|