diff --git a/Source/Plugins/JuliaProcessor/JuliaEditor.cpp b/Source/Plugins/JuliaProcessor/JuliaEditor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..929d134998e4d8b2a9924b184340657cc86e27ce --- /dev/null +++ b/Source/Plugins/JuliaProcessor/JuliaEditor.cpp @@ -0,0 +1,151 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + 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 3 of the License, or + (at your option) 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "JuliaEditor.h" +#include "JuliaProcessor.h" +#include <stdio.h> + +JuliaEditor::JuliaEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors=true) + : GenericEditor(parentNode, useDefaultParameterEditors) +{ + juliaProcessor = (JuliaProcessor*) parentNode; + + lastFilePath = File::getCurrentWorkingDirectory(); + + fileButton = new UtilityButton("Select file",Font("Small Text", 13, Font::plain)); + fileButton->addListener(this); + fileButton->setBounds(10,85,100,25); + addAndMakeVisible(fileButton); + + reloadFileButton = new UtilityButton("refresh",Font("Small Text", 13, Font::plain)); + reloadFileButton->addListener(this); + reloadFileButton->setBounds(100+10,85,60,25); + addAndMakeVisible(reloadFileButton); + + fileNameLabel = new Label("FileNameLabel", "No file selected."); + fileNameLabel->setBounds(10,85+20,140,25); + addAndMakeVisible(fileNameLabel); + + bufferSizeSelection = new Label("Buffer Size","30000"); // this is currently set in RHD2000Thread, the cleaner would be to set it here again + bufferSizeSelection->setEditable(true,false,false); + bufferSizeSelection->addListener(this); + bufferSizeSelection->setBounds(120,60,60,20); + bufferSizeSelection->setColour(Label::textColourId, Colours::darkgrey); + addAndMakeVisible(bufferSizeSelection); + + bufferSizeSelectionLabel = new Label("","NBuf.:"); + bufferSizeSelectionLabel->attachToComponent (bufferSizeSelection,true); + addAndMakeVisible(bufferSizeSelectionLabel); + + // Image im; + // im = ImageCache::getFromMemory(BinaryData::JuliaIconActive_png, + // BinaryData::JuliaIconActive_pngSize); + + // icon = new ImageIcon(im); + // addAndMakeVisible(icon); + // icon->setBounds(15,25,61,54); + // icon->setOpacity(0.3f); + + desiredWidth = 200; + + setEnabledState(false); +} + +JuliaEditor::~JuliaEditor() +{ + +} + +void JuliaEditor::setFile(String file) +{ + File fileToRead(file); + lastFilePath = fileToRead.getParentDirectory(); + juliaProcessor->setFile(fileToRead.getFullPathName()); + fileNameLabel->setText(fileToRead.getFileName(), dontSendNotification); + + + // setEnabledState(true); + // icon->setOpacity(1.0f); // tie this to hasJuliaInstance instead of just setting it! + // repaint(); +} + +void JuliaEditor::buttonEvent(Button* button) +{ + if (!acquisitionIsActive) + { + if (button == fileButton) + { + //std::cout << "Button clicked." << std::endl; + //FileChooser chooseJuliaProcessorFile("Please select the file you want to load...", lastFilePath, "*"); + + + // file dialogs are screwed up in current xubuntu, so we'll do this for now. + setFile("/home/jvoigts/Documents/Github/plugin-GUI/Source/Plugins/JuliaProcessor/exampleProcessor.jl"); + + + // if (chooseJuliaProcessorFile.browseForFileToOpen()) + { + // Use the selected file + //setFile(chooseJuliaProcessorFile.getResult().getFullPathName()); + + // lastFilePath = fileToRead.getParentDirectory(); + // thread->setFile(fileToRead.getFullPathName()); + // fileNameLabel->setText(fileToRead.getFileName(),false); + } + } + if (button == reloadFileButton) + { + juliaProcessor->reloadFile(); + } + } +} + +void JuliaEditor::labelTextChanged(Label* label) +{ + if (!acquisitionIsActive) + { + if (label == bufferSizeSelection) + { + Value val = label->getTextValue(); + juliaProcessor->setBuffersize(int(val.getValue())); + } + } +} + +void JuliaEditor::saveEditorParameters(XmlElement* xml) +{ + // XmlElement* fileName = xml->createNewChildElement("FILENAME"); + // fileName->addTextElement(lastFilePath.getFullPathName()); +} + +void JuliaEditor::loadEditorParameters(XmlElement* xml) +{ + // forEachXmlChildElement(*xml, xmlNode) + // { + // if (xmlNode->hasTagName("FILENAME")) + // { + // lastFilePath = File(xmlNode->getText()); + // thread->setFile(lastFilePath.getFullPathName()); + // fileNameLabel->setText(lastFilePath.getFullPathName(),false); + // } + // } +} \ No newline at end of file diff --git a/Source/Plugins/JuliaProcessor/JuliaEditor.h b/Source/Plugins/JuliaProcessor/JuliaEditor.h new file mode 100644 index 0000000000000000000000000000000000000000..6aec266254260644b8aa185aec953b9f167c46a9 --- /dev/null +++ b/Source/Plugins/JuliaProcessor/JuliaEditor.h @@ -0,0 +1,64 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + 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 3 of the License, or + (at your option) 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef JULIAEDITOR_H_INCLUDED +#define JULIAEDITOR_H_INCLUDED + +#include <EditorHeaders.h> + +//class ImageIcon; +class JuliaProcessor; + +/** + + User interface for the Julia processor. + + @see JuliaProcessor + +*/ + +class JuliaEditor : public GenericEditor, public Label::Listener + +{ +public: + JuliaEditor(GenericProcessor* parentNode, bool useDefaultParameterEditors); + virtual ~JuliaEditor(); + void buttonEvent(Button* button); + void labelTextChanged(Label* te); + void setFile(String file); + void saveEditorParameters(XmlElement*); + void loadEditorParameters(XmlElement*); + ImageIcon* icon; + +private: + ScopedPointer<UtilityButton> fileButton; + ScopedPointer<UtilityButton> reloadFileButton; + ScopedPointer<Label> fileNameLabel; + ScopedPointer<Label> bufferSizeSelection; + ScopedPointer<Label> bufferSizeSelectionLabel; + JuliaProcessor* juliaProcessor; + File lastFilePath; + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JuliaEditor); +}; + +#endif // JULIAEDITOR_H_INCLUDED \ No newline at end of file diff --git a/Source/Plugins/JuliaProcessor/JuliaProcessor.cpp b/Source/Plugins/JuliaProcessor/JuliaProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..561369399955720153f974ca8d842909659e9cd5 --- /dev/null +++ b/Source/Plugins/JuliaProcessor/JuliaProcessor.cpp @@ -0,0 +1,169 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + 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 3 of the License, or + (at your option) 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "JuliaProcessor.h" +#include "JuliaEditor.h" +#include <stdio.h> +#include <julia.h> + +JuliaProcessor::JuliaProcessor() + : GenericProcessor("Julia Processor") +{ + hasJuliaInstance = false; + dataHistoryBufferNumChannels = 256; + dataHistoryBuffer = new AudioSampleBuffer(dataHistoryBufferNumChannels, 60000); + dataHistoryBuffer->clear(); +} + +JuliaProcessor::~JuliaProcessor() +{ + jl_atexit_hook(0); + deleteAndZero(dataHistoryBuffer); +} + +AudioProcessorEditor* JuliaProcessor::createEditor() +{ + editor = new JuliaEditor(this, true); + std::cout << "Creating Julia editor." << std::endl; + return editor; +} + +void JuliaProcessor::setFile(String fullpath) +{ + hasJuliaInstance = true; + filePath = fullpath; + + FILE* fp = popen("echo $JULIA", "r"); + char input[255]; + fgets(input, sizeof(input), fp); + + String julia_bin_dir = input; + julia_bin_dir = julia_bin_dir.trimEnd(); + julia_bin_dir += "/home/jvoigts/Documents/Github/julia/usr/bin"; + String julia_sys_dir = input; + julia_sys_dir = julia_sys_dir.trimEnd(); + julia_sys_dir += "/home/jvoigts/Documents/Github/julia/usr/lib/julia/sys.so"; + + const char* jbin = julia_bin_dir.toRawUTF8(); + const char* jsys = julia_sys_dir.toRawUTF8(); + + jl_init_with_image(jbin, jsys); + + String juliaString = "include(\"" + filePath + "\")"; + run_julia_string(juliaString); +} + +void JuliaProcessor::reloadFile() +{ + if (hasJuliaInstance) + { + String juliaString = "reload(\"" + filePath + "\")"; + run_julia_string(juliaString); + } + else + { + std::cout << "No julia instance running - cant refresh" << std::endl; + } +} + + +void JuliaProcessor::setParameter(int parameterIndex, float newValue) +{ + editor->updateParameterButtons(parameterIndex); +} + +void JuliaProcessor::setBuffersize(int bufferSize) +{ + if (bufferSize > 1) + { + dataHistoryBufferSize=bufferSize; + printf("Setting history buffer size to %d samples \n", dataHistoryBufferSize); + dataHistoryBuffer->setSize(dataHistoryBufferNumChannels, dataHistoryBufferSize, false, true, false); + } + else + { + printf("History buffer size has to be at least 1"); + } +} + +void JuliaProcessor::run_julia_string(String juliaString) +{ + // need to convert from juce String to char array + const char* jstr = juliaString.toRawUTF8(); + + printf("executing julia cmd: %s\n", jstr); + + jl_eval_string(jstr); + + if (jl_exception_occurred()) + printf("%s \n", jl_typeof_str(jl_exception_occurred())); +} + + + +String JuliaProcessor::getFile() +{ + return filePath; +} + +void JuliaProcessor::process(AudioSampleBuffer& buffer, MidiBuffer& midiMessages) +{ + if (hasJuliaInstance) + { + jl_function_t *func = jl_get_function(jl_main_module, "oe_process!"); + + // create 2D array of float64 type + jl_value_t *array_type = jl_apply_array_type(jl_float32_type, 1); // last arg is nDims + + for (int n = 0; n < getNumOutputs(); n++) + { + float* ptr = buffer.getWritePointer(n); // to perform in-place edits to the buffer + jl_array_t *x = jl_ptr_to_array_1d(array_type, ptr , buffer.getNumSamples(), 0); + JL_GC_PUSH1(&x); + jl_call1(func, (jl_value_t*)x); + JL_GC_POP(); + } + } +} + +void JuliaProcessor::saveCustomParametersToXml(XmlElement* parentElement) +{ + XmlElement* childNode = parentElement->createNewChildElement("FILENAME"); + childNode->setAttribute("path", getFile()); +} + +void JuliaProcessor::loadCustomParametersFromXml() +{ + if (parametersAsXml != nullptr) + { + // use parametersAsXml to restore state + forEachXmlChildElement(*parametersAsXml, xmlNode) + { + if (xmlNode->hasTagName("FILENAME")) + { + String filepath = xmlNode->getStringAttribute("path"); + JuliaEditor* fre = (JuliaEditor*) getEditor(); + fre->setFile(filepath); + } + } + } +} \ No newline at end of file diff --git a/Source/Plugins/JuliaProcessor/JuliaProcessor.h b/Source/Plugins/JuliaProcessor/JuliaProcessor.h new file mode 100644 index 0000000000000000000000000000000000000000..eed4a215d1631462ba7c2e1d091c486e77b33e4c --- /dev/null +++ b/Source/Plugins/JuliaProcessor/JuliaProcessor.h @@ -0,0 +1,68 @@ +/* + ------------------------------------------------------------------ + + This file is part of the Open Ephys GUI + Copyright (C) 2016 Open Ephys + + ------------------------------------------------------------------ + + 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 3 of the License, or + (at your option) 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef JULIAPROCESSOR_H_INCLUDED +#define JULIAPROCESSOR_H_INCLUDED + +#include <ProcessorHeaders.h> + +/** + Julia Processor. + + Allows the user to select a Julia Programming Language file to use as filter + + @see GenericProcessor, JuliaEditor +*/ + +class JuliaProcessor : public GenericProcessor + +{ +public: + JuliaProcessor(); + ~JuliaProcessor(); + void setFile(String fullpath); + String getFile(); + void reloadFile(); + void process(AudioSampleBuffer& buffer, MidiBuffer& midiMessages); + void setParameter(int parameterIndex, float newValue); + void setBuffersize(int bufferSize); + AudioProcessorEditor* createEditor(); + bool hasEditor() const + { + return true; + } + void saveCustomParametersToXml(XmlElement* parentElement); + void loadCustomParametersFromXml(); + +private: + bool hasJuliaInstance; + String filePath; + int dataHistoryBufferSize; + int dataHistoryBufferNumChannels; + AudioSampleBuffer* dataHistoryBuffer; + void run_julia_string(String juliaString); + + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JuliaProcessor); +}; + + +#endif // JULIAPROCESSOR_H_INCLUDED diff --git a/Source/Plugins/JuliaProcessor/Makefile b/Source/Plugins/JuliaProcessor/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..cf44ee2e6a80ca742b7e3ed76b73332e6636b410 --- /dev/null +++ b/Source/Plugins/JuliaProcessor/Makefile @@ -0,0 +1,45 @@ + +LIBNAME := $(notdir $(CURDIR)) +OBJDIR := $(OBJDIR)/$(LIBNAME) +TARGET := $(LIBNAME).so + + +SRC_DIR := ${shell find ./ -type d -print} +VPATH := $(SOURCE_DIRS) + +SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp)) +OBJ := $(addprefix $(OBJDIR)/,$(notdir $(SRC:.cpp=.o))) + + +JULIA = /home/jvoigts/Documents/Github/julia/ + +# flags to compile "JuliaProcessor". $(JULIA): toplevel of julia package +CXXFLAGS += -I $(JULIA)/src -I $(JULIA)/src/support -I $(JULIA)/usr/include +LDFLAGS += -L $(JULIA)/usr/lib -Wl,-R $(JULIA)/usr/lib -ljulia + +BLDCMD := $(CXX) -shared -o $(OUTDIR)/$(TARGET) $(OBJ) $(LDFLAGS) $(RESOURCES) $(TARGET_ARCH) + +VPATH = $(SRC_DIR) + +.PHONY: objdir + +$(OUTDIR)/$(TARGET): objdir $(OBJ) + -@mkdir -p $(BINDIR) + -@mkdir -p $(LIBDIR) + -@mkdir -p $(OUTDIR) + @echo "Building $(TARGET)" + @$(BLDCMD) + +$(OBJDIR)/%.o : %.cpp + @echo "Compiling $<" + @$(CXX) $(CXXFLAGS) -o "$@" -c "$<" + +objdir: + -@mkdir -p $(OBJDIR) + +clean: + @echo "Cleaning $(LIBNAME)" + -@rm -rf $(OBJDIR) + -@rm -f $(OUTDIR)/$(TARGET) + +-include $(OBJ:%.o=%.d) diff --git a/Source/Plugins/JuliaProcessor/OpenEphysLib.cpp b/Source/Plugins/JuliaProcessor/OpenEphysLib.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30f7449643972822bcbc46914ca6992193346266 --- /dev/null +++ b/Source/Plugins/JuliaProcessor/OpenEphysLib.cpp @@ -0,0 +1,70 @@ +/* +------------------------------------------------------------------ + +This file is part of the Open Ephys GUI +Copyright (C) 2016 Open Ephys + +------------------------------------------------------------------ + +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 3 of the License, or +(at your option) 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. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <PluginInfo.h> +#include "JuliaProcessor.h" +#include <string> +#ifdef WIN32 +#include <Windows.h> +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +using namespace Plugin; +#define NUM_PLUGINS 1 + +extern "C" EXPORT void getLibInfo(Plugin::LibraryInfo* info) +{ + info->apiVersion = PLUGIN_API_VER; + info->name = "Julia Processor"; + info->libVersion = 1; + info->numPlugins = NUM_PLUGINS; +} + +extern "C" EXPORT int getPluginInfo(int index, Plugin::PluginInfo* info) +{ + switch (index) + { + case 0: + info->type = Plugin::ProcessorPlugin; + info->processor.name = "Julia Processor"; + info->processor.type = Plugin::FilterProcessor; + info->processor.creator = &(Plugin::createProcessor<JuliaProcessor>); + break; + default: + return -1; + break; + } + return 0; +} + +#ifdef WIN32 +BOOL WINAPI DllMain(IN HINSTANCE hDllHandle, + IN DWORD nReason, + IN LPVOID Reserved) +{ + return TRUE; +} + +#endif \ No newline at end of file