@@ -28,6 +28,13 @@ class Window; | |||
class App | |||
{ | |||
public: | |||
class IdleCallback | |||
{ | |||
public: | |||
~IdleCallback() {} | |||
virtual void idleCallback() = 0; | |||
}; | |||
App(); | |||
~App(); | |||
@@ -36,15 +43,18 @@ public: | |||
void quit(); | |||
bool isQuiting() const; | |||
void addIdleCallback(IdleCallback* const callback); | |||
void removeIdleCallback(IdleCallback* const callback); | |||
private: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
friend class Window; | |||
void addWindow(Window* const window); | |||
void removeWindow(Window* const window); | |||
void oneShown(); | |||
void oneHidden(); | |||
void _addWindow(Window* const window); | |||
void _removeWindow(Window* const window); | |||
void _oneShown(); | |||
void _oneHidden(); | |||
}; | |||
// ----------------------------------------------------------------------- |
@@ -39,8 +39,10 @@ | |||
#endif | |||
#ifndef PROPER_CPP11_SUPPORT | |||
# ifndef __clang__ | |||
# define noexcept throw() | |||
# endif | |||
# define override | |||
# define noexcept throw() | |||
# define nullptr (0) | |||
#endif | |||
@@ -21,6 +21,8 @@ | |||
#include <cairo.h> | |||
#include <cstdio> | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
@@ -36,56 +38,63 @@ public: | |||
{ | |||
} | |||
protected: | |||
virtual void cairoDisplay(cairo_t* const context) = 0; | |||
private: | |||
void onReshape(int width, int height) override | |||
virtual void setWidth(int width) override | |||
{ | |||
// handle resize | |||
setSize(width, height); | |||
Widget::onReshape(width, height); | |||
if (fArea.getWidth() == width) | |||
return; | |||
// free previous if needed | |||
onClose(); | |||
Widget::setWidth(width); | |||
_recreateSurface(); | |||
} | |||
// create new | |||
fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); | |||
fContext = cairo_create(fSurface); | |||
virtual void setHeight(int height) override | |||
{ | |||
if (fArea.getHeight() == height) | |||
return; | |||
glGenTextures(1, &fTextureId); | |||
Widget::setHeight(height); | |||
_recreateSurface(); | |||
} | |||
void onClose() override | |||
virtual void setSize(const Size<int>& size) override | |||
{ | |||
if (fContext != nullptr) | |||
{ | |||
cairo_destroy(fContext); | |||
fContext = nullptr; | |||
} | |||
if (fArea.getSize() == size) | |||
return; | |||
if (fSurface != nullptr) | |||
{ | |||
cairo_surface_destroy(fSurface); | |||
fSurface = nullptr; | |||
} | |||
Widget::setSize(size); | |||
_recreateSurface(); | |||
} | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
void setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
protected: | |||
virtual void cairoDisplay(cairo_t* const context) = 0; | |||
private: | |||
void onDisplay() override | |||
{ | |||
// wait for first resize | |||
// wait for sizing | |||
if (fSurface == nullptr || fContext == nullptr) | |||
{ | |||
glClear(GL_COLOR_BUFFER_BIT); | |||
printf("invalid surface\n"); | |||
return; | |||
} | |||
if (fTextureId == 0) | |||
glGenTextures(1, &fTextureId); | |||
if (fTextureId == 0) | |||
{ | |||
// TODO: invalidate widget | |||
printf("invalid texture\n"); | |||
return; | |||
} | |||
#if 1 | |||
const int x = getX(); | |||
const int y = getY(); | |||
const int width = getWidth(); | |||
const int height = getHeight(); | |||
@@ -108,25 +117,80 @@ private: | |||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, surfaceData); | |||
// draw the texture | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
glBegin(GL_QUADS); | |||
glTexCoord2i(0, height); | |||
glVertex2i(0, height); | |||
// glBegin(GL_QUADS); | |||
// glTexCoord2f(0.0f, 0.0f); | |||
// glVertex2i(x, y); | |||
// | |||
// glTexCoord2f(1.0f, 0.0f); | |||
// glVertex2i(x+width, y); | |||
// | |||
// glTexCoord2f(1.0f, 1.0f); | |||
// glVertex2i(x+width, y+height); | |||
// | |||
// glTexCoord2f(0.0f, 1.0f); | |||
// glVertex2i(x, y+height); | |||
// glEnd(); | |||
glTexCoord2i(width, height); | |||
glVertex2i(width, height); | |||
glBegin(GL_QUADS); | |||
//glTexCoord2i(x, y); | |||
glTexCoord2i(0, 0); | |||
glVertex2i(x, y); | |||
//glTexCoord2i(x+width, y); | |||
glTexCoord2i(width, 0); | |||
glVertex2i(width, 0); | |||
glVertex2i(x+width, y); | |||
glTexCoord2i(0, 0); | |||
glVertex2i(0, 0); | |||
//glTexCoord2i(x+width, y+height); | |||
glTexCoord2i(width, height); | |||
glVertex2i(x+width, y+height); | |||
//glTexCoord2i(x, y+height); | |||
glTexCoord2i(0, height); | |||
glVertex2i(x, y+height); | |||
glEnd(); | |||
// cleanup | |||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); | |||
glDisable(GL_TEXTURE_RECTANGLE_ARB); | |||
#endif | |||
} | |||
void onClose() override | |||
{ | |||
if (fContext != nullptr) | |||
{ | |||
cairo_destroy(fContext); | |||
fContext = nullptr; | |||
} | |||
if (fSurface != nullptr) | |||
{ | |||
cairo_surface_destroy(fSurface); | |||
fSurface = nullptr; | |||
} | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
} | |||
void _recreateSurface() | |||
{ | |||
if (fContext != nullptr) | |||
cairo_destroy(fContext); | |||
if (fSurface != nullptr) | |||
cairo_surface_destroy(fSurface); | |||
fSurface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, fArea.getWidth(), fArea.getHeight()); | |||
if (fSurface != nullptr) | |||
fContext = cairo_create(fSurface); | |||
else | |||
fContext = nullptr; | |||
} | |||
private: |
@@ -30,6 +30,7 @@ public: | |||
Image(const char* rawData, int width, int height, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
Image(const char* rawData, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
Image(const Image& image) noexcept; | |||
~Image(); | |||
void loadFromMemory(const char* rawData, int width, int height, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
void loadFromMemory(const char* rawData, const Size<int>& size, GLenum format = GL_BGRA, GLenum type = GL_UNSIGNED_BYTE) noexcept; | |||
@@ -44,9 +45,9 @@ public: | |||
GLenum getFormat() const noexcept; | |||
GLenum getType() const noexcept; | |||
void draw() const; | |||
void draw(int x, int y) const; | |||
void draw(const Point<int>& pos) const; | |||
void draw(); | |||
void draw(int x, int y); | |||
void draw(const Point<int>& pos); | |||
Image& operator=(const Image& image) noexcept; | |||
bool operator==(const Image& image) const noexcept; | |||
@@ -57,6 +58,7 @@ private: | |||
Size<int> fSize; | |||
GLenum fFormat; | |||
GLenum fType; | |||
GLuint fTextureId; | |||
}; | |||
// ----------------------------------------------------------------------- |
@@ -4,7 +4,7 @@ | |||
# Created by falkTX | |||
# | |||
include ../../../Makefile.mk | |||
include ../Makefile.mk | |||
# -------------------------------------------------------------- | |||
@@ -80,42 +80,42 @@ endif | |||
# -------------------------------------------------------------- | |||
all: ../../dgl.a | |||
all: ../dgl.a | |||
posix32: ../../dgl.posix32.a | |||
posix64: ../../dgl.posix64.a | |||
win32: ../../dgl.win32.a | |||
win64: ../../dgl.win64.a | |||
posix32: ../dgl.posix32.a | |||
posix64: ../dgl.posix64.a | |||
win32: ../dgl.win32.a | |||
win64: ../dgl.win64.a | |||
# -------------------------------------------------------------- | |||
../../dgl.a: $(OBJS) | |||
../dgl.a: $(OBJS) | |||
$(RM) $@ | |||
$(AR) crs $@ $^ | |||
../../dgl.posix32.a: $(OBJS_posix32) | |||
../dgl.posix32.a: $(OBJS_posix32) | |||
$(RM) $@ | |||
$(AR) crs $@ $^ | |||
../../dgl.posix64.a: $(OBJS_posix64) | |||
../dgl.posix64.a: $(OBJS_posix64) | |||
$(RM) $@ | |||
$(AR) crs $@ $^ | |||
../../dgl.win32.a: $(OBJS_win32) | |||
../dgl.win32.a: $(OBJS_win32) | |||
$(RM) $@ | |||
$(AR) crs $@ $^ | |||
../../dgl.win64.a: $(OBJS_win64) | |||
../dgl.win64.a: $(OBJS_win64) | |||
$(RM) $@ | |||
$(AR) crs $@ $^ | |||
../../libdgl.dll: $(OBJS) | |||
../libdgl.dll: $(OBJS) | |||
$(CXX) $^ -shared $(LINK_FLAGS) -o $@ | |||
../../libdgl.dylib: $(OBJS) | |||
../libdgl.dylib: $(OBJS) | |||
$(CXX) $^ -dynamiclib $(LINK_FLAGS) -o $@ | |||
../../libdgl.so: $(OBJS) | |||
../libdgl.so: $(OBJS) | |||
$(CXX) $^ -shared $(LINK_FLAGS) -o $@ | |||
# -------------------------------------------------------------- | |||
@@ -136,12 +136,12 @@ win64: ../../dgl.win64.a | |||
$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ | |||
%.m.o: %.m | |||
$(CC) $< $(BUILD_C_FLAGS) -objc -c -o $@ | |||
$(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@ | |||
# -------------------------------------------------------------- | |||
clean: | |||
$(RM) src/*.o src/pugl/*.o ../../dgl*.a ../../libdgl.* | |||
$(RM) src/*.o src/pugl/*.o ../dgl*.a ../libdgl.* | |||
debug: | |||
$(MAKE) DEBUG=true |
@@ -60,10 +60,15 @@ public: | |||
int getHeight() const noexcept; | |||
const Size<int>& getSize() const noexcept; | |||
void setWidth(int width); | |||
void setHeight(int height); | |||
void setSize(int width, int height); | |||
void setSize(const Size<int>& size); | |||
// virtual needed by cairo | |||
virtual void setWidth(int width); | |||
virtual void setHeight(int height); | |||
virtual void setSize(const Size<int>& size); | |||
void setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
const Rectangle<int>& getArea() const noexcept; | |||
@@ -80,7 +85,7 @@ protected: | |||
virtual bool onKeyboard(bool press, uint32_t key); | |||
virtual bool onMouse(int button, bool press, int x, int y); | |||
virtual bool onMotion(int x, int y); | |||
virtual bool onScroll(float dx, float dy); | |||
virtual bool onScroll(int x, int y, float dx, float dy); | |||
virtual bool onSpecial(bool press, Key key); | |||
virtual void onReshape(int width, int height); | |||
virtual void onClose(); | |||
@@ -90,6 +95,7 @@ private: | |||
bool fVisible; | |||
Rectangle<int> fArea; | |||
friend class CairoWidget; | |||
friend class Window; | |||
}; | |||
@@ -46,7 +46,6 @@ public: | |||
void exec(bool lockWait = false); | |||
void focus(); | |||
void idle(); | |||
void repaint(); | |||
bool isVisible() const noexcept; | |||
@@ -55,11 +54,9 @@ public: | |||
bool isResizable() const noexcept; | |||
void setResizable(bool yesNo); | |||
#ifndef DGL_OS_MAC | |||
int getWidth() const noexcept; | |||
int getHeight() const noexcept; | |||
Size<int> getSize() const noexcept; | |||
#endif | |||
void setSize(unsigned int width, unsigned int height); | |||
void setTitle(const char* title); | |||
@@ -72,10 +69,12 @@ public: | |||
private: | |||
class PrivateData; | |||
PrivateData* const pData; | |||
friend class App; | |||
friend class Widget; | |||
void addWidget(Widget* const widget); | |||
void removeWidget(Widget* const widget); | |||
void _addWidget(Widget* const widget); | |||
void _removeWidget(Widget* const widget); | |||
void _idle(); | |||
}; | |||
// ----------------------------------------------------------------------- |
@@ -27,6 +27,7 @@ struct App::PrivateData { | |||
bool doLoop; | |||
unsigned visibleWindows; | |||
std::list<Window*> windows; | |||
std::list<IdleCallback*> idleCallbacks; | |||
PrivateData() | |||
: doLoop(false), | |||
@@ -43,6 +44,7 @@ App::App() | |||
App::~App() | |||
{ | |||
pData->windows.clear(); | |||
pData->idleCallbacks.clear(); | |||
delete pData; | |||
} | |||
@@ -51,7 +53,13 @@ void App::idle() | |||
for (std::list<Window*>::iterator it = pData->windows.begin(); it != pData->windows.end(); ++it) | |||
{ | |||
Window* const window(*it); | |||
window->idle(); | |||
window->_idle(); | |||
} | |||
for (std::list<IdleCallback*>::iterator it = pData->idleCallbacks.begin(); it != pData->idleCallbacks.end(); ++it) | |||
{ | |||
IdleCallback* const idleCallback(*it); | |||
idleCallback->idleCallback(); | |||
} | |||
} | |||
@@ -82,25 +90,39 @@ bool App::isQuiting() const | |||
// ----------------------------------------------------------------------- | |||
void App::addWindow(Window* const window) | |||
void App::addIdleCallback(IdleCallback* const callback) | |||
{ | |||
if (callback != nullptr) | |||
pData->idleCallbacks.push_back(callback); | |||
} | |||
void App::removeIdleCallback(IdleCallback* const callback) | |||
{ | |||
if (callback != nullptr) | |||
pData->idleCallbacks.remove(callback); | |||
} | |||
// ----------------------------------------------------------------------- | |||
void App::_addWindow(Window* const window) | |||
{ | |||
if (window != nullptr) | |||
pData->windows.push_back(window); | |||
} | |||
void App::removeWindow(Window* const window) | |||
void App::_removeWindow(Window* const window) | |||
{ | |||
if (window != nullptr) | |||
pData->windows.remove(window); | |||
} | |||
void App::oneShown() | |||
void App::_oneShown() | |||
{ | |||
if (++pData->visibleWindows == 1) | |||
pData->doLoop = true; | |||
} | |||
void App::oneHidden() | |||
void App::_oneHidden() | |||
{ | |||
if (--pData->visibleWindows == 0) | |||
pData->doLoop = false; |
@@ -24,7 +24,8 @@ Image::Image() noexcept | |||
: fRawData(nullptr), | |||
fSize(0, 0), | |||
fFormat(0), | |||
fType(0) | |||
fType(0), | |||
fTextureId(0) | |||
{ | |||
} | |||
@@ -32,7 +33,8 @@ Image::Image(const char* rawData, int width, int height, GLenum format, GLenum t | |||
: fRawData(rawData), | |||
fSize(width, height), | |||
fFormat(format), | |||
fType(type) | |||
fType(type), | |||
fTextureId(0) | |||
{ | |||
} | |||
@@ -40,7 +42,8 @@ Image::Image(const char* rawData, const Size<int>& size, GLenum format, GLenum t | |||
: fRawData(rawData), | |||
fSize(size), | |||
fFormat(format), | |||
fType(type) | |||
fType(type), | |||
fTextureId(0) | |||
{ | |||
} | |||
@@ -48,10 +51,20 @@ Image::Image(const Image& image) noexcept | |||
: fRawData(image.fRawData), | |||
fSize(image.fSize), | |||
fFormat(image.fFormat), | |||
fType(image.fType) | |||
fType(image.fType), | |||
fTextureId(0) | |||
{ | |||
} | |||
Image::~Image() | |||
{ | |||
if (fTextureId != 0) | |||
{ | |||
glDeleteTextures(1, &fTextureId); | |||
fTextureId = 0; | |||
} | |||
} | |||
void Image::loadFromMemory(const char* rawData, int width, int height, GLenum format, GLenum type) noexcept | |||
{ | |||
loadFromMemory(rawData, Size<int>(width, height), format, type); | |||
@@ -100,27 +113,67 @@ GLenum Image::getType() const noexcept | |||
return fType; | |||
} | |||
void Image::draw() const | |||
void Image::draw() | |||
{ | |||
draw(0, 0); | |||
} | |||
void Image::draw(int x, int y) const | |||
void Image::draw(int x, int y) | |||
{ | |||
if (! isValid()) | |||
return; | |||
if (fTextureId == 0) | |||
glGenTextures(1, &fTextureId); | |||
if (fTextureId == 0) | |||
{ | |||
// invalidate image | |||
fSize = Size<int>(0, 0); | |||
return; | |||
} | |||
glEnable(GL_TEXTURE_2D); | |||
glBindTexture(GL_TEXTURE_2D, fTextureId); | |||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | |||
glPixelStorei(GL_PACK_ALIGNMENT, 1); | |||
glRasterPos2i(x, fSize.getHeight()+y); | |||
glDrawPixels(fSize.getWidth(), fSize.getHeight(), fFormat, fType, fRawData); | |||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getWidth(), getHeight(), 0, fFormat, fType, fRawData); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | |||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | |||
float trans[] = { 0.0f, 0.0f, 0.0f, 0.0f }; | |||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, trans); | |||
const int width = getWidth(); | |||
const int height = getHeight(); | |||
glBegin(GL_QUADS); | |||
glTexCoord2f(0.0f, 0.0f); | |||
glVertex2i(x, y); | |||
glTexCoord2f(1.0f, 0.0f); | |||
glVertex2i(x+width, y); | |||
glTexCoord2f(1.0f, 1.0f); | |||
glVertex2i(x+width, y+height); | |||
glTexCoord2f(0.0f, 1.0f); | |||
glVertex2i(x, y+height); | |||
glEnd(); | |||
glBindTexture(GL_TEXTURE_2D, 0); | |||
glDisable(GL_TEXTURE_2D); | |||
} | |||
void Image::draw(const Point<int>& pos) const | |||
void Image::draw(const Point<int>& pos) | |||
{ | |||
draw(pos.getX(), pos.getY()); | |||
} | |||
// ----------------------------------------------------------------------- | |||
Image& Image::operator=(const Image& image) noexcept | |||
{ | |||
fRawData = image.fRawData; |
@@ -16,13 +16,6 @@ | |||
#include "../ImageAboutWindow.hpp" | |||
// FIXME: 32bit hack | |||
#if ! (defined (__LP64__) || defined (_LP64) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) | |||
# define PAD_SIZE +1 | |||
#else | |||
# define PAD_SIZE | |||
#endif | |||
START_NAMESPACE_DGL | |||
// ----------------------------------------------------------------------- | |||
@@ -32,7 +25,8 @@ ImageAboutWindow::ImageAboutWindow(App& app, Window& parent, const Image& image) | |||
Widget((Window&)*this), | |||
fImgBackground(image) | |||
{ | |||
Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE); | |||
Window::setResizable(false); | |||
Window::setSize(image.getWidth(), image.getHeight()); | |||
Window::setTitle("About"); | |||
} | |||
@@ -41,14 +35,15 @@ ImageAboutWindow::ImageAboutWindow(Widget* widget, const Image& image) | |||
Widget((Window&)*this), | |||
fImgBackground(image) | |||
{ | |||
Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE); | |||
Window::setResizable(false); | |||
Window::setSize(image.getWidth(), image.getHeight()); | |||
Window::setTitle("About"); | |||
} | |||
void ImageAboutWindow::setImage(const Image& image) | |||
{ | |||
fImgBackground = image; | |||
Window::setSize(image.getWidth(), image.getHeight() PAD_SIZE); | |||
Window::setSize(image.getWidth(), image.getHeight()); | |||
} | |||
void ImageAboutWindow::onDisplay() |
@@ -29,12 +29,12 @@ Widget::Widget(Window& parent) | |||
: fParent(parent), | |||
fVisible(true) | |||
{ | |||
fParent.addWidget(this); | |||
fParent._addWidget(this); | |||
} | |||
Widget::~Widget() | |||
{ | |||
fParent.removeWidget(this); | |||
fParent._removeWidget(this); | |||
} | |||
bool Widget::isVisible() const noexcept | |||
@@ -153,11 +153,6 @@ void Widget::setHeight(int height) | |||
fParent.repaint(); | |||
} | |||
void Widget::setSize(int width, int height) | |||
{ | |||
setSize(Size<int>(width, height)); | |||
} | |||
void Widget::setSize(const Size<int>& size) | |||
{ | |||
if (fArea.getSize() == size) | |||
@@ -212,7 +207,7 @@ bool Widget::onMotion(int, int) | |||
return false; | |||
} | |||
bool Widget::onScroll(float, float) | |||
bool Widget::onScroll(int, int, float, float) | |||
{ | |||
return false; | |||
} |
@@ -19,6 +19,7 @@ | |||
#include "../Window.hpp" | |||
#include <cassert> | |||
#include <cstdio> | |||
#include <list> | |||
#include "pugl/pugl.h" | |||
@@ -26,9 +27,12 @@ | |||
#if DGL_OS_WINDOWS | |||
# include "pugl/pugl_win.cpp" | |||
#elif DGL_OS_MAC | |||
extern "C" { | |||
# include "pugl/pugl_osx_extended.h" | |||
} | |||
extern "C" { | |||
struct PuglViewImpl { | |||
int width; | |||
int height; | |||
};} | |||
#elif DGL_OS_LINUX | |||
extern "C" { | |||
# include "pugl/pugl_x11.c" | |||
@@ -43,6 +47,16 @@ extern "C" { | |||
#define FOR_EACH_WIDGET_INV(rit) \ | |||
for (std::list<Widget*>::reverse_iterator rit = fWidgets.rbegin(); rit != fWidgets.rend(); ++rit) | |||
#ifdef DEBUG | |||
# define DBG(msg) std::fprintf(stderr, "%s", msg); | |||
# define DBGp(...) std::fprintf(stderr, __VA_ARGS__); | |||
# define DBGF std::fflush(stderr); | |||
#else | |||
# define DBG(msg) | |||
# define DBGp(...) | |||
# define DBGF | |||
#endif | |||
START_NAMESPACE_DGL | |||
Window* dgl_lastUiParent = nullptr; | |||
@@ -60,6 +74,7 @@ public: | |||
fFirstInit(true), | |||
fVisible(false), | |||
fResizable(true), | |||
fUsingEmbed(false), | |||
#if DGL_OS_WINDOWS | |||
hwnd(0) | |||
#elif DGL_OS_LINUX | |||
@@ -69,6 +84,7 @@ public: | |||
_dummy('\0') | |||
#endif | |||
{ | |||
DBG("Creating window without parent..."); DBGF; | |||
init(); | |||
} | |||
@@ -79,6 +95,7 @@ public: | |||
fFirstInit(true), | |||
fVisible(false), | |||
fResizable(true), | |||
fUsingEmbed(false), | |||
fModal(parent.pData), | |||
#if DGL_OS_WINDOWS | |||
hwnd(0) | |||
@@ -89,13 +106,13 @@ public: | |||
_dummy('\0') | |||
#endif | |||
{ | |||
DBG("Creating window with parent..."); DBGF; | |||
init(); | |||
#if DGL_OS_LINUX | |||
PuglInternals* const parentImpl = parent.pData->fView->impl; | |||
const PuglInternals* const parentImpl(parent.pData->fView->impl); | |||
XSetTransientForHint(xDisplay, xWindow, parentImpl->win); | |||
XFlush(xDisplay); | |||
#endif | |||
} | |||
@@ -106,6 +123,7 @@ public: | |||
fFirstInit(true), | |||
fVisible(true), | |||
fResizable(false), | |||
fUsingEmbed(true), | |||
#if DGL_OS_WINDOWS | |||
hwnd(0) | |||
#elif DGL_OS_LINUX | |||
@@ -115,17 +133,22 @@ public: | |||
_dummy('\0') | |||
#endif | |||
{ | |||
DBG("Creating embedded window..."); DBGF; | |||
init(); | |||
// starts visible | |||
fApp.oneShown(); | |||
DBG("NOTE: Embed window is always visible and non-resizable\n"); | |||
fApp._oneShown(); | |||
fFirstInit = false; | |||
} | |||
void init() | |||
{ | |||
if (fView == nullptr) | |||
if (fSelf == nullptr || fView == nullptr) | |||
{ | |||
DBG("Failed!\n"); | |||
dgl_lastUiParent = nullptr; | |||
return; | |||
} | |||
dgl_lastUiParent = fSelf; | |||
@@ -142,47 +165,73 @@ public: | |||
#if DGL_OS_WINDOWS | |||
PuglInternals* impl = fView->impl; | |||
hwnd = impl->hwnd; | |||
assert(hwnd != 0); | |||
#elif DGL_OS_LINUX | |||
PuglInternals* impl = fView->impl; | |||
xDisplay = impl->display; | |||
xWindow = impl->win; | |||
assert(xWindow != 0); | |||
#endif | |||
fApp.addWindow(fSelf); | |||
DBG("Success!\n"); | |||
// process any initial events | |||
puglProcessEvents(fView); | |||
fApp._addWindow(fSelf); | |||
} | |||
~PrivateData() | |||
{ | |||
DBG("Destroying window..."); DBGF; | |||
//fOnModal = false; | |||
fWidgets.clear(); | |||
if (fSelf != nullptr) | |||
{ | |||
fApp._removeWindow(fSelf); | |||
fSelf = nullptr; | |||
} | |||
if (fView != nullptr) | |||
{ | |||
fApp.removeWindow(fSelf); | |||
puglDestroy(fView); | |||
fView = nullptr; | |||
} | |||
#if DGL_OS_WINDOWS | |||
hwnd = 0; | |||
#elif DGL_OS_LINUX | |||
xDisplay = nullptr; | |||
xWindow = 0; | |||
#endif | |||
DBG("Success!\n"); | |||
} | |||
// ------------------------------------------------------------------- | |||
void close() | |||
{ | |||
DBG("Window close\n"); | |||
setVisible(false); | |||
if (! fFirstInit) | |||
{ | |||
fApp.oneHidden(); | |||
fApp._oneHidden(); | |||
fFirstInit = true; | |||
} | |||
} | |||
void exec(const bool lockWait) | |||
{ | |||
DBG("Window exec\n"); | |||
exec_init(); | |||
if (lockWait) | |||
{ | |||
while (fVisible && fModal.enabled) | |||
for (; fVisible && fModal.enabled;) | |||
{ | |||
// idle() | |||
puglProcessEvents(fView); | |||
@@ -205,6 +254,7 @@ public: | |||
void focus() | |||
{ | |||
DBG("Window focus\n"); | |||
#if DGL_OS_WINDOWS | |||
SetForegroundWindow(hwnd); | |||
SetActiveWindow(hwnd); | |||
@@ -218,16 +268,9 @@ public: | |||
#endif | |||
} | |||
void idle() | |||
{ | |||
puglProcessEvents(fView); | |||
if (fVisible && fModal.enabled && fModal.parent != nullptr) | |||
fModal.parent->idle(); | |||
} | |||
void repaint() | |||
{ | |||
//DBG("Window repaint\n"); | |||
puglPostRedisplay(fView); | |||
} | |||
@@ -241,27 +284,28 @@ public: | |||
void setVisible(const bool yesNo) | |||
{ | |||
if (fVisible == yesNo) | |||
{ | |||
DBG("Window setVisible matches current state, ignoring request\n"); | |||
return; | |||
} | |||
if (fUsingEmbed) | |||
{ | |||
DBG("Window setVisible cannot be called when embedded\n"); | |||
return; | |||
} | |||
DBG("Window setVisible called\n"); | |||
fVisible = yesNo; | |||
#ifndef DGL_OS_MAC | |||
if (yesNo && fFirstInit) | |||
setSize(fView->width, fView->height, true); | |||
#endif | |||
#if DGL_OS_WINDOWS | |||
if (yesNo) | |||
{ | |||
ShowWindow(hwnd, WS_VISIBLE); | |||
if (! fFirstInit) | |||
ShowWindow(hwnd, SW_RESTORE); | |||
} | |||
ShowWindow(hwnd, fFirstInit ? SW_SHOWNORMAL : SW_RESTORE); | |||
else | |||
{ | |||
ShowWindow(hwnd, SW_HIDE); | |||
} | |||
UpdateWindow(hwnd); | |||
#elif DGL_OS_MAC | |||
@@ -279,7 +323,7 @@ public: | |||
{ | |||
if (fFirstInit) | |||
{ | |||
fApp.oneShown(); | |||
fApp._oneShown(); | |||
fFirstInit = false; | |||
} | |||
} | |||
@@ -297,18 +341,25 @@ public: | |||
void setResizable(const bool yesNo) | |||
{ | |||
if (fResizable == yesNo) | |||
{ | |||
DBG("Window setResizable matches current state, ignoring request\n"); | |||
return; | |||
} | |||
if (fUsingEmbed) | |||
{ | |||
DBG("Window setResizable cannot be called when embedded\n"); | |||
return; | |||
} | |||
DBG("Window setResizable called\n"); | |||
fResizable = yesNo; | |||
#ifndef DGL_OS_MAC | |||
setSize(fView->width, fView->height, true); | |||
#endif | |||
} | |||
// ------------------------------------------------------------------- | |||
#ifndef DGL_OS_MAC | |||
int getWidth() const noexcept | |||
{ | |||
return fView->width; | |||
@@ -323,22 +374,25 @@ public: | |||
{ | |||
return Size<int>(fView->width, fView->height); | |||
} | |||
#endif | |||
void setSize(unsigned int width, unsigned int height, const bool forced = false) | |||
{ | |||
if (width == 0) | |||
width = 1; | |||
if (height == 0) | |||
height = 1; | |||
if (width == 0 || height == 0) | |||
{ | |||
DBGp("Window setSize called with invalid value(s) %i %i, ignoring request\n", width, height); | |||
return; | |||
} | |||
#ifndef DGL_OS_MAC | |||
if (fView->width == (int)width && fView->height == (int)height && ! forced) | |||
return; | |||
if (fView->width == static_cast<int>(width) && fView->height == static_cast<int>(height) && ! forced) | |||
{ | |||
DBG("Window setSize matches current size, ignoring request\n"); | |||
return; | |||
} | |||
fView->width = width; | |||
fView->height = height; | |||
#endif | |||
DBGp("Window setSize called %s\n", forced ? "(forced)" : "(not forced)"); | |||
#if DGL_OS_WINDOWS | |||
int winFlags = WS_POPUPWINDOW | WS_CAPTION; | |||
@@ -346,13 +400,15 @@ public: | |||
if (fResizable) | |||
winFlags |= WS_SIZEBOX; | |||
RECT wr = { 0, 0, (long)width, (long)height }; | |||
RECT wr = { 0, 0, static_cast<long>(width), static_cast<long>(height) }; | |||
AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); | |||
SetWindowPos(hwnd, 0, 0, 0, wr.right-wr.left, wr.bottom-wr.top, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER); | |||
UpdateWindow(hwnd); | |||
if (! forced) | |||
UpdateWindow(hwnd); | |||
#elif DGL_OS_MAC | |||
puglImplSetSize(fView, width, height); | |||
puglImplSetSize(fView, width, height, forced); | |||
#elif DGL_OS_LINUX | |||
XResizeWindow(xDisplay, xWindow, width, height); | |||
@@ -370,7 +426,8 @@ public: | |||
XSetNormalHints(xDisplay, xWindow, &sizeHints); | |||
} | |||
XFlush(xDisplay); | |||
if (! forced) | |||
XFlush(xDisplay); | |||
#endif | |||
repaint(); | |||
@@ -380,13 +437,14 @@ public: | |||
void setTitle(const char* const title) | |||
{ | |||
DBGp("Window setTitle \"%s\"\n", title); | |||
#if DGL_OS_WINDOWS | |||
SetWindowTextA(hwnd, title); | |||
#elif DGL_OS_MAC | |||
puglImplSetTitle(fView, title); | |||
#elif DGL_OS_LINUX | |||
XStoreName(xDisplay, xWindow, title); | |||
XFlush(xDisplay); | |||
#endif | |||
} | |||
@@ -422,16 +480,28 @@ public: | |||
fWidgets.remove(widget); | |||
} | |||
void idle() | |||
{ | |||
puglProcessEvents(fView); | |||
if (fModal.enabled && fModal.parent != nullptr) | |||
fModal.parent->idle(); | |||
} | |||
// ------------------------------------------------------------------- | |||
void exec_init() | |||
{ | |||
fModal.enabled = true; | |||
DBG("Window modal loop starting..."); DBGF; | |||
assert(fModal.parent != nullptr); | |||
if (fModal.parent == nullptr) | |||
{ | |||
DBG("Failed, there's no modal parent!\n"); | |||
return setVisible(true); | |||
} | |||
fModal.enabled = true; | |||
fModal.parent->fModal.childFocus = this; | |||
#if DGL_OS_WINDOWS | |||
@@ -452,14 +522,19 @@ public: | |||
fModal.parent->setVisible(true); | |||
setVisible(true); | |||
DBG("Ok\n"); | |||
} | |||
void exec_fini() | |||
{ | |||
DBG("Window modal loop stopping..."); DBGF; | |||
fModal.enabled = false; | |||
if (fModal.parent != nullptr) | |||
fModal.parent->fModal.childFocus = nullptr; | |||
DBG("Ok\n"); | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -467,6 +542,8 @@ public: | |||
protected: | |||
void onDisplay() | |||
{ | |||
//DBG("PUGL: onDisplay\n"); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
FOR_EACH_WIDGET(it) | |||
@@ -480,6 +557,8 @@ protected: | |||
void onKeyboard(const bool press, const uint32_t key) | |||
{ | |||
DBGp("PUGL: onKeyboard : %i %i\n", press, key); | |||
if (fModal.childFocus != nullptr) | |||
return fModal.childFocus->focus(); | |||
@@ -494,6 +573,8 @@ protected: | |||
void onMouse(const int button, const bool press, const int x, const int y) | |||
{ | |||
DBGp("PUGL: onMouse : %i %i %i %i\n", button, press, x, y); | |||
if (fModal.childFocus != nullptr) | |||
return fModal.childFocus->focus(); | |||
@@ -508,6 +589,8 @@ protected: | |||
void onMotion(const int x, const int y) | |||
{ | |||
DBGp("PUGL: onMotion : %i %i\n", x, y); | |||
if (fModal.childFocus != nullptr) | |||
return; | |||
@@ -520,8 +603,10 @@ protected: | |||
} | |||
} | |||
void onScroll(const float dx, const float dy) | |||
void onScroll(const int x, const int y, const float dx, const float dy) | |||
{ | |||
DBGp("PUGL: onScroll : %i %i %f %f\n", x, y, dx, dy); | |||
if (fModal.childFocus != nullptr) | |||
return; | |||
@@ -529,13 +614,15 @@ protected: | |||
{ | |||
Widget* const widget(*rit); | |||
if (widget->isVisible() && widget->onScroll(dx, dy)) | |||
if (widget->isVisible() && widget->onScroll(x, y, dx, dy)) | |||
break; | |||
} | |||
} | |||
void onSpecial(const bool press, const Key key) | |||
{ | |||
DBGp("PUGL: onSpecial : %i %i\n", press, key); | |||
if (fModal.childFocus != nullptr) | |||
return; | |||
@@ -550,7 +637,8 @@ protected: | |||
void onReshape(const int width, const int height) | |||
{ | |||
printf("resized: %i:%i\n", width, height); | |||
DBGp("PUGL: onReshape : %i %i\n", width, height); | |||
FOR_EACH_WIDGET(it) | |||
{ | |||
Widget* const widget(*it); | |||
@@ -560,7 +648,10 @@ protected: | |||
void onClose() | |||
{ | |||
fModal.enabled = false; | |||
DBG("PUGL: onClose\n"); | |||
if (fModal.enabled && fModal.parent != nullptr) | |||
exec_fini(); | |||
if (fModal.childFocus != nullptr) | |||
fModal.childFocus->onClose(); | |||
@@ -577,13 +668,14 @@ protected: | |||
// ------------------------------------------------------------------- | |||
private: | |||
App& fApp; | |||
Window* const fSelf; | |||
PuglView* const fView; | |||
App& fApp; | |||
Window* fSelf; | |||
PuglView* fView; | |||
bool fFirstInit; | |||
bool fVisible; | |||
bool fResizable; | |||
bool fUsingEmbed; | |||
std::list<Widget*> fWidgets; | |||
struct Modal { | |||
@@ -642,9 +734,9 @@ private: | |||
handlePtr->onMotion(x, y); | |||
} | |||
static void onScrollCallback(PuglView* view, float dx, float dy) | |||
static void onScrollCallback(PuglView* view, int x, int y, float dx, float dy) | |||
{ | |||
handlePtr->onScroll(dx, dy); | |||
handlePtr->onScroll(x, y, dx, dy); | |||
} | |||
static void onSpecialCallback(PuglView* view, bool press, PuglKey key) | |||
@@ -713,11 +805,6 @@ void Window::focus() | |||
pData->focus(); | |||
} | |||
void Window::idle() | |||
{ | |||
pData->idle(); | |||
} | |||
void Window::repaint() | |||
{ | |||
pData->repaint(); | |||
@@ -743,7 +830,6 @@ void Window::setResizable(bool yesNo) | |||
pData->setResizable(yesNo); | |||
} | |||
#ifndef DGL_OS_MAC | |||
int Window::getWidth() const noexcept | |||
{ | |||
return pData->getWidth(); | |||
@@ -758,7 +844,6 @@ Size<int> Window::getSize() const noexcept | |||
{ | |||
return pData->getSize(); | |||
} | |||
#endif | |||
void Window::setSize(unsigned int width, unsigned int height) | |||
{ | |||
@@ -790,16 +875,24 @@ intptr_t Window::getWindowId() const | |||
return pData->getWindowId(); | |||
} | |||
void Window::addWidget(Widget* const widget) | |||
void Window::_addWidget(Widget* const widget) | |||
{ | |||
pData->addWidget(widget); | |||
} | |||
void Window::removeWidget(Widget* const widget) | |||
void Window::_removeWidget(Widget* const widget) | |||
{ | |||
pData->removeWidget(widget); | |||
} | |||
void Window::_idle() | |||
{ | |||
pData->idle(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DGL | |||
#undef DBG | |||
#undef DBGF |
@@ -95,7 +95,7 @@ typedef enum { | |||
PUGL_CHAR_ESCAPE = 0x1B, | |||
PUGL_CHAR_DELETE = 0x7F | |||
} PuglChar; | |||
/** | |||
Special (non-Unicode) keyboard keys. | |||
*/ | |||
@@ -131,12 +131,12 @@ typedef enum { | |||
Keyboard modifier flags. | |||
*/ | |||
typedef enum { | |||
PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||
PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||
} PuglMod; | |||
/** | |||
Handle for opaque user data. | |||
*/ | |||
@@ -199,13 +199,17 @@ typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | |||
@param dx The scroll x distance. | |||
@param dx The scroll y distance. | |||
*/ | |||
typedef void (*PuglScrollFunc)(PuglView* view, float dx, float dy); | |||
typedef void (*PuglScrollFunc)(PuglView* view, | |||
int x, | |||
int y, | |||
float dx, | |||
float dy); | |||
/** | |||
A function called when a special key is pressed or released. | |||
This callback allows the use of keys that do not have unicode points. Note | |||
that some non-printable keys | |||
This callback allows the use of keys that do not have unicode points. | |||
@param view The view the event occured in. | |||
@param press True if the key was pressed, false if released. | |||
@param key The key pressed. |
@@ -20,10 +20,27 @@ | |||
Note this file contains function definitions, so it must be compiled into | |||
the final binary exactly once. Each platform specific implementation file | |||
including it once should achieve this. | |||
If you are copying the pugl code into your source tree, the following | |||
symbols can be defined to tweak pugl behaviour: | |||
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||
PUGL_VERBOSE: Print GL information to console. | |||
*/ | |||
#include "pugl.h" | |||
#ifdef PUGL_VERBOSE | |||
# include <stdio.h> | |||
# define PUGL_LOG(str) fprintf(stderr, "pugl: " str) | |||
# define PUGL_LOGF(fmt, ...) fprintf(stderr, "pugl: " fmt, __VA_ARGS__) | |||
#else | |||
# define PUGL_LOG(str) | |||
# define PUGL_LOGF(fmt, ...) | |||
#endif | |||
void puglDefaultReshape(PuglView* view, int width, int height); | |||
typedef struct PuglInternalsImpl PuglInternals; | |||
struct PuglViewImpl { |
@@ -36,6 +36,7 @@ | |||
defer:(BOOL)flag; | |||
- (void) setPuglview:(PuglView*)view; | |||
- (BOOL) windowShouldClose:(id)sender; | |||
- (BOOL) canBecomeKeyWindow:(id)sender; | |||
@end | |||
@implementation PuglWindow | |||
@@ -70,6 +71,11 @@ | |||
return YES; | |||
} | |||
- (BOOL) canBecomeKeyWindow:(id)sender | |||
{ | |||
return NO; | |||
} | |||
@end | |||
void | |||
@@ -99,6 +105,7 @@ puglDisplay(PuglView* view) | |||
- (void) mouseDragged:(NSEvent*)event; | |||
- (void) mouseDown:(NSEvent*)event; | |||
- (void) mouseUp:(NSEvent*)event; | |||
- (void) rightMouseDragged:(NSEvent*)event; | |||
- (void) rightMouseDown:(NSEvent*)event; | |||
- (void) rightMouseUp:(NSEvent*)event; | |||
- (void) keyDown:(NSEvent*)event; | |||
@@ -181,6 +188,10 @@ getModifiers(PuglView* view, NSEvent* ev) | |||
view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); | |||
double ts = [ev timestamp] * 1000.0; | |||
ts = (uint32)ts % 500000; //ridiculously large vals won't fit | |||
view->event_timestamp_ms = ts; | |||
unsigned mods = 0; | |||
mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; | |||
mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; | |||
@@ -233,6 +244,15 @@ getModifiers(PuglView* view, NSEvent* ev) | |||
} | |||
} | |||
- (void) rightMouseDragged:(NSEvent*)event | |||
{ | |||
if (puglview->motionFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) mouseDown:(NSEvent*)event | |||
{ | |||
if (puglview->mouseFunc) { | |||
@@ -273,8 +293,11 @@ getModifiers(PuglView* view, NSEvent* ev) | |||
- (void) scrollWheel:(NSEvent*)event | |||
{ | |||
if (puglview->scrollFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->scrollFunc(puglview, [event deltaX], [event deltaY]); | |||
puglview->scrollFunc(puglview, | |||
loc.x, puglview->height - loc.y, | |||
[event deltaX], [event deltaY]); | |||
} | |||
[self updateTrackingAreas]; | |||
} | |||
@@ -359,6 +382,7 @@ puglCreate(PuglNativeWindow parent, | |||
[window setContentView:impl->glview]; | |||
[NSApp activateIgnoringOtherApps:YES]; | |||
[window makeFirstResponder:impl->glview]; | |||
[window makeKeyAndOrderFront:window]; | |||
if (! visible) { |
@@ -106,8 +106,12 @@ puglCreate(PuglNativeWindow parent, | |||
free(view); | |||
return NULL; | |||
} | |||
#ifdef _WIN64 | |||
SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); | |||
#else | |||
SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view); | |||
#endif | |||
impl->hdc = GetDC(impl->hwnd); | |||
@@ -145,7 +149,7 @@ puglDestroy(PuglView* view) | |||
free(view); | |||
} | |||
static void | |||
void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
@@ -285,22 +289,26 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
break; | |||
case WM_MOUSEWHEEL: | |||
if (view->scrollFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->scrollFunc( | |||
view, 0, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); | |||
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | |||
0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); | |||
} | |||
break; | |||
case WM_MOUSEHWHEEL: | |||
if (view->scrollFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->scrollFunc( | |||
view, (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0); | |||
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | |||
(int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); | |||
} | |||
break; | |||
case WM_KEYDOWN: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | |||
break; | |||
} // else nobreak | |||
case WM_KEYUP: | |||
view->event_timestamp_ms = GetMessageTime(); | |||
if ((key = keySymToSpecial(wParam))) { | |||
if (view->specialFunc) { | |||
view->specialFunc(view, message == WM_KEYDOWN, key); | |||
@@ -342,7 +350,12 @@ puglProcessEvents(PuglView* view) | |||
LRESULT CALLBACK | |||
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||
{ | |||
#ifdef _WIN64 | |||
PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); | |||
#else | |||
PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA); | |||
#endif | |||
switch (message) { | |||
case WM_CREATE: | |||
PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); |
@@ -1,7 +1,6 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||
Copyright 2013 Robin Gareus <robin@gareus.org> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -32,16 +31,6 @@ | |||
#include "pugl_internal.h" | |||
/* work around buggy re-parent & focus issues on some systems | |||
* where no keyboard events are passed through even if the | |||
* app has mouse-focus and all other events are working. | |||
*/ | |||
#define XKEYFOCUSGRAB | |||
/* show messages during initalization | |||
*/ | |||
//#define VERBOSE_PUGL | |||
struct PuglInternalsImpl { | |||
Display* display; | |||
int screen; | |||
@@ -101,21 +90,15 @@ puglCreate(PuglNativeWindow parent, | |||
if (!vi) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
impl->doubleBuffered = False; | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: singlebuffered rendering will be used, no doublebuffering available\n"); | |||
#endif | |||
PUGL_LOG("No double buffering available\n"); | |||
} else { | |||
impl->doubleBuffered = True; | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: doublebuffered rendering available\n"); | |||
#endif | |||
PUGL_LOG("Double buffered rendering enabled\n"); | |||
} | |||
int glxMajor, glxMinor; | |||
glXQueryVersion(impl->display, &glxMajor, &glxMinor); | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor); | |||
#endif | |||
PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
@@ -168,13 +151,9 @@ puglCreate(PuglNativeWindow parent, | |||
} | |||
if (glXIsDirect(impl->display, impl->ctx)) { | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: DRI enabled\n"); | |||
#endif | |||
PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||
} else { | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: No DRI available\n"); | |||
#endif | |||
PUGL_LOG("No DRI available\n"); | |||
} | |||
XFree(vi); | |||
@@ -196,7 +175,7 @@ puglDestroy(PuglView* view) | |||
free(view); | |||
} | |||
static void | |||
void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
@@ -211,7 +190,7 @@ puglReshape(PuglView* view, int width, int height) | |||
view->height = height; | |||
} | |||
static void | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
@@ -279,6 +258,27 @@ setModifiers(PuglView* view, unsigned xstate, unsigned xtime) | |||
view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; | |||
} | |||
static void | |||
dispatchKey(PuglView* view, XEvent* event, bool press) | |||
{ | |||
KeySym sym; | |||
char str[5]; | |||
const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); | |||
if (n == 0) { | |||
return; | |||
} else if (n > 1) { | |||
fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); | |||
return; | |||
} | |||
const PuglKey special = keySymToSpecial(sym); | |||
if (special && view->specialFunc) { | |||
view->specialFunc(view, press, special); | |||
} else if (!special && view->keyboardFunc) { | |||
view->keyboardFunc(view, press, str[0]); | |||
} | |||
} | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
@@ -320,7 +320,9 @@ puglProcessEvents(PuglView* view) | |||
case 6: dx = -1.0f; break; | |||
case 7: dx = 1.0f; break; | |||
} | |||
view->scrollFunc(view, dx, dy); | |||
view->scrollFunc(view, | |||
event.xbutton.x, event.xbutton.y, | |||
dx, dy); | |||
} | |||
break; | |||
} | |||
@@ -334,25 +336,12 @@ puglProcessEvents(PuglView* view) | |||
event.xbutton.x, event.xbutton.y); | |||
} | |||
break; | |||
case KeyPress: { | |||
case KeyPress: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
KeySym sym; | |||
char str[5]; | |||
int n = XLookupString(&event.xkey, str, 4, &sym, NULL); | |||
PuglKey key = keySymToSpecial(sym); | |||
if (!key && view->keyboardFunc) { | |||
if (n == 1) { | |||
view->keyboardFunc(view, true, str[0]); | |||
} else { | |||
fprintf(stderr, "warning: Unknown key %X\n", (int)sym); | |||
} | |||
} else if (view->specialFunc) { | |||
view->specialFunc(view, true, key); | |||
} | |||
} break; | |||
case KeyRelease: { | |||
dispatchKey(view, &event, true); | |||
break; | |||
case KeyRelease: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
bool repeated = false; | |||
if (view->ignoreKeyRepeat && | |||
XEventsQueued(view->impl->display, QueuedAfterReading)) { | |||
XEvent next; | |||
@@ -361,20 +350,11 @@ puglProcessEvents(PuglView* view) | |||
next.xkey.time == event.xkey.time && | |||
next.xkey.keycode == event.xkey.keycode) { | |||
XNextEvent(view->impl->display, &event); | |||
repeated = true; | |||
break; | |||
} | |||
} | |||
if (!repeated && view->keyboardFunc) { | |||
KeySym sym = XLookupKeysym(&event.xkey, 0); | |||
PuglKey special = keySymToSpecial(sym); | |||
if (!special) { | |||
view->keyboardFunc(view, false, sym); | |||
} else if (view->specialFunc) { | |||
view->specialFunc(view, false, special); | |||
} | |||
} | |||
} break; | |||
dispatchKey(view, &event, false); | |||
break; | |||
case ClientMessage: | |||
if (!strcmp(XGetAtomName(view->impl->display, | |||
event.xclient.message_type), | |||
@@ -384,9 +364,12 @@ puglProcessEvents(PuglView* view) | |||
} | |||
} | |||
break; | |||
#ifdef XKEYFOCUSGRAB | |||
#ifdef PUGL_GRAB_FOCUS | |||
case EnterNotify: | |||
XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); | |||
XSetInputFocus(view->impl->display, | |||
view->impl->win, | |||
RevertToPointerRoot, | |||
CurrentTime); | |||
break; | |||
#endif | |||
default: |
@@ -0,0 +1,357 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file pugl.h API for Pugl, a minimal portable API for OpenGL. | |||
*/ | |||
#ifndef PUGL_H_INCLUDED | |||
#define PUGL_H_INCLUDED | |||
#include <stdint.h> | |||
/* | |||
This API is pure portable C and contains no platform specific elements, or | |||
even a GL dependency. However, unfortunately GL includes vary across | |||
platforms so they are included here to allow for pure portable programs. | |||
*/ | |||
#ifdef __APPLE__ | |||
# include "OpenGL/gl.h" | |||
#else | |||
# ifdef _WIN32 | |||
# include <windows.h> /* Broken Windows GL headers require this */ | |||
# endif | |||
# include "GL/gl.h" | |||
#endif | |||
#ifdef PUGL_SHARED | |||
# ifdef _WIN32 | |||
# define PUGL_LIB_IMPORT __declspec(dllimport) | |||
# define PUGL_LIB_EXPORT __declspec(dllexport) | |||
# else | |||
# define PUGL_LIB_IMPORT __attribute__((visibility("default"))) | |||
# define PUGL_LIB_EXPORT __attribute__((visibility("default"))) | |||
# endif | |||
# ifdef PUGL_INTERNAL | |||
# define PUGL_API PUGL_LIB_EXPORT | |||
# else | |||
# define PUGL_API PUGL_LIB_IMPORT | |||
# endif | |||
#else | |||
# define PUGL_API | |||
#endif | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** | |||
@defgroup pugl Pugl | |||
A minimal portable API for OpenGL. | |||
@{ | |||
*/ | |||
/** | |||
An OpenGL view. | |||
*/ | |||
typedef struct PuglViewImpl PuglView; | |||
/** | |||
A native window handle. | |||
On X11, this is a Window. | |||
On OSX, this is an NSView*. | |||
On Windows, this is a HWND. | |||
*/ | |||
typedef intptr_t PuglNativeWindow; | |||
/** | |||
Return status code. | |||
*/ | |||
typedef enum { | |||
PUGL_SUCCESS = 0 | |||
} PuglStatus; | |||
/** | |||
Convenience symbols for ASCII control characters. | |||
*/ | |||
typedef enum { | |||
PUGL_CHAR_BACKSPACE = 0x08, | |||
PUGL_CHAR_ESCAPE = 0x1B, | |||
PUGL_CHAR_DELETE = 0x7F | |||
} PuglChar; | |||
/** | |||
Special (non-Unicode) keyboard keys. | |||
*/ | |||
typedef enum { | |||
PUGL_KEY_F1 = 1, | |||
PUGL_KEY_F2, | |||
PUGL_KEY_F3, | |||
PUGL_KEY_F4, | |||
PUGL_KEY_F5, | |||
PUGL_KEY_F6, | |||
PUGL_KEY_F7, | |||
PUGL_KEY_F8, | |||
PUGL_KEY_F9, | |||
PUGL_KEY_F10, | |||
PUGL_KEY_F11, | |||
PUGL_KEY_F12, | |||
PUGL_KEY_LEFT, | |||
PUGL_KEY_UP, | |||
PUGL_KEY_RIGHT, | |||
PUGL_KEY_DOWN, | |||
PUGL_KEY_PAGE_UP, | |||
PUGL_KEY_PAGE_DOWN, | |||
PUGL_KEY_HOME, | |||
PUGL_KEY_END, | |||
PUGL_KEY_INSERT, | |||
PUGL_KEY_SHIFT, | |||
PUGL_KEY_CTRL, | |||
PUGL_KEY_ALT, | |||
PUGL_KEY_SUPER | |||
} PuglKey; | |||
/** | |||
Keyboard modifier flags. | |||
*/ | |||
typedef enum { | |||
PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||
} PuglMod; | |||
/** | |||
Handle for opaque user data. | |||
*/ | |||
typedef void* PuglHandle; | |||
/** | |||
A function called when the window is closed. | |||
*/ | |||
typedef void (*PuglCloseFunc)(PuglView* view); | |||
/** | |||
A function called to draw the view contents with OpenGL. | |||
*/ | |||
typedef void (*PuglDisplayFunc)(PuglView* view); | |||
/** | |||
A function called when a key is pressed or released. | |||
@param view The view the event occured in. | |||
@param press True if the key was pressed, false if released. | |||
@param key Unicode point of the key pressed. | |||
*/ | |||
typedef void (*PuglKeyboardFunc)(PuglView* view, bool press, uint32_t key); | |||
/** | |||
A function called when the pointer moves. | |||
@param view The view the event occured in. | |||
@param x The window-relative x coordinate of the pointer. | |||
@param y The window-relative y coordinate of the pointer. | |||
*/ | |||
typedef void (*PuglMotionFunc)(PuglView* view, int x, int y); | |||
/** | |||
A function called when a mouse button is pressed or released. | |||
@param view The view the event occured in. | |||
@param button The button number (1 = left, 2 = middle, 3 = right). | |||
@param press True if the key was pressed, false if released. | |||
@param x The window-relative x coordinate of the pointer. | |||
@param y The window-relative y coordinate of the pointer. | |||
*/ | |||
typedef void (*PuglMouseFunc)( | |||
PuglView* view, int button, bool press, int x, int y); | |||
/** | |||
A function called when the view is resized. | |||
@param view The view being resized. | |||
@param width The new view width. | |||
@param height The new view height. | |||
*/ | |||
typedef void (*PuglReshapeFunc)(PuglView* view, int width, int height); | |||
/** | |||
A function called on scrolling (e.g. mouse wheel or track pad). | |||
The distances used here are in "lines", a single tick of a clicking mouse | |||
wheel. For example, @p dy = 1.0 scrolls 1 line up. Some systems and | |||
devices support finer resolution and/or higher values for fast scrolls, | |||
so programs should handle any value gracefully. | |||
@param view The view being scrolled. | |||
@param dx The scroll x distance. | |||
@param dx The scroll y distance. | |||
*/ | |||
typedef void (*PuglScrollFunc)(PuglView* view, | |||
int x, | |||
int y, | |||
float dx, | |||
float dy); | |||
/** | |||
A function called when a special key is pressed or released. | |||
This callback allows the use of keys that do not have unicode points. | |||
@param view The view the event occured in. | |||
@param press True if the key was pressed, false if released. | |||
@param key The key pressed. | |||
*/ | |||
typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||
/** | |||
Create a new GL window. | |||
@param parent Parent window, or 0 for top level. | |||
@param title Window title, or NULL. | |||
@param width Window width in pixels. | |||
@param height Window height in pixels. | |||
@param resizable Whether window should be user resizable. | |||
@param visible Whether window should be initially visible. | |||
*/ | |||
PUGL_API PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible); | |||
/** | |||
Set the handle to be passed to all callbacks. | |||
This is generally a pointer to a struct which contains all necessary state. | |||
Everything needed in callbacks should be here, not in static variables. | |||
Note the lack of this facility makes GLUT unsuitable for plugins or | |||
non-trivial programs; this mistake is largely why Pugl exists. | |||
*/ | |||
PUGL_API void | |||
puglSetHandle(PuglView* view, PuglHandle handle); | |||
/** | |||
Get the handle to be passed to all callbacks. | |||
*/ | |||
PUGL_API PuglHandle | |||
puglGetHandle(PuglView* view); | |||
/** | |||
Return the timestamp (if any) of the currently-processing event. | |||
*/ | |||
PUGL_API uint32_t | |||
puglGetEventTimestamp(PuglView* view); | |||
/** | |||
Get the currently active modifiers (PuglMod flags). | |||
This should only be called from an event handler. | |||
*/ | |||
PUGL_API int | |||
puglGetModifiers(PuglView* view); | |||
/** | |||
Ignore synthetic repeated key events. | |||
*/ | |||
PUGL_API void | |||
puglIgnoreKeyRepeat(PuglView* view, bool ignore); | |||
/** | |||
Set the function to call when the window is closed. | |||
*/ | |||
PUGL_API void | |||
puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc); | |||
/** | |||
Set the display function which should draw the UI using GL. | |||
*/ | |||
PUGL_API void | |||
puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc); | |||
/** | |||
Set the function to call on keyboard events. | |||
*/ | |||
PUGL_API void | |||
puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc); | |||
/** | |||
Set the function to call on mouse motion. | |||
*/ | |||
PUGL_API void | |||
puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc); | |||
/** | |||
Set the function to call on mouse button events. | |||
*/ | |||
PUGL_API void | |||
puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc); | |||
/** | |||
Set the function to call on scroll events. | |||
*/ | |||
PUGL_API void | |||
puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc); | |||
/** | |||
Set the function to call on special events. | |||
*/ | |||
PUGL_API void | |||
puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc); | |||
/** | |||
Set the function to call when the window size changes. | |||
*/ | |||
PUGL_API void | |||
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc); | |||
/** | |||
Return the native window handle. | |||
*/ | |||
PUGL_API PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view); | |||
/** | |||
Process all pending window events. | |||
This handles input events as well as rendering, so it should be called | |||
regularly and rapidly enough to keep the UI responsive. | |||
*/ | |||
PUGL_API PuglStatus | |||
puglProcessEvents(PuglView* view); | |||
/** | |||
Request a redisplay on the next call to puglProcessEvents(). | |||
*/ | |||
PUGL_API void | |||
puglPostRedisplay(PuglView* view); | |||
/** | |||
Destroy a GL window. | |||
*/ | |||
PUGL_API void | |||
puglDestroy(PuglView* view); | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* PUGL_H_INCLUDED */ |
@@ -0,0 +1,161 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file pugl_internal.h Private platform-independent definitions. | |||
Note this file contains function definitions, so it must be compiled into | |||
the final binary exactly once. Each platform specific implementation file | |||
including it once should achieve this. | |||
If you are copying the pugl code into your source tree, the following | |||
symbols can be defined to tweak pugl behaviour: | |||
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||
PUGL_VERBOSE: Print GL information to console. | |||
*/ | |||
#include "pugl.h" | |||
#ifdef PUGL_VERBOSE | |||
# include <stdio.h> | |||
# define PUGL_LOG(str) fprintf(stderr, "pugl: " str) | |||
# define PUGL_LOGF(fmt, ...) fprintf(stderr, "pugl: " fmt, __VA_ARGS__) | |||
#else | |||
# define PUGL_LOG(str) | |||
# define PUGL_LOGF(fmt, ...) | |||
#endif | |||
void puglDefaultReshape(PuglView* view, int width, int height); | |||
typedef struct PuglInternalsImpl PuglInternals; | |||
struct PuglViewImpl { | |||
int width; | |||
int height; | |||
PuglHandle handle; | |||
PuglCloseFunc closeFunc; | |||
PuglDisplayFunc displayFunc; | |||
PuglKeyboardFunc keyboardFunc; | |||
PuglMotionFunc motionFunc; | |||
PuglMouseFunc mouseFunc; | |||
PuglReshapeFunc reshapeFunc; | |||
PuglScrollFunc scrollFunc; | |||
PuglSpecialFunc specialFunc; | |||
PuglInternals* impl; | |||
int mods; | |||
bool mouse_in_view; | |||
bool ignoreKeyRepeat; | |||
bool redisplay; | |||
uint32_t event_timestamp_ms; | |||
}; | |||
void | |||
puglSetHandle(PuglView* view, PuglHandle handle) | |||
{ | |||
view->handle = handle; | |||
} | |||
PuglHandle | |||
puglGetHandle(PuglView* view) | |||
{ | |||
return view->handle; | |||
} | |||
uint32_t | |||
puglGetEventTimestamp(PuglView* view) | |||
{ | |||
return view->event_timestamp_ms; | |||
} | |||
int | |||
puglGetModifiers(PuglView* view) | |||
{ | |||
return view->mods; | |||
} | |||
void | |||
puglDefaultReshape(PuglView* view, int width, int height) | |||
{ | |||
glMatrixMode(GL_PROJECTION); | |||
glLoadIdentity(); | |||
glOrtho(0, width, height, 0, 0, 1); | |||
glViewport(0, 0, width, height); | |||
glMatrixMode(GL_MODELVIEW); | |||
glLoadIdentity(); | |||
return; | |||
// unused | |||
(void)view; | |||
} | |||
void | |||
puglIgnoreKeyRepeat(PuglView* view, bool ignore) | |||
{ | |||
view->ignoreKeyRepeat = ignore; | |||
} | |||
void | |||
puglSetCloseFunc(PuglView* view, PuglCloseFunc closeFunc) | |||
{ | |||
view->closeFunc = closeFunc; | |||
} | |||
void | |||
puglSetDisplayFunc(PuglView* view, PuglDisplayFunc displayFunc) | |||
{ | |||
view->displayFunc = displayFunc; | |||
} | |||
void | |||
puglSetKeyboardFunc(PuglView* view, PuglKeyboardFunc keyboardFunc) | |||
{ | |||
view->keyboardFunc = keyboardFunc; | |||
} | |||
void | |||
puglSetMotionFunc(PuglView* view, PuglMotionFunc motionFunc) | |||
{ | |||
view->motionFunc = motionFunc; | |||
} | |||
void | |||
puglSetMouseFunc(PuglView* view, PuglMouseFunc mouseFunc) | |||
{ | |||
view->mouseFunc = mouseFunc; | |||
} | |||
void | |||
puglSetReshapeFunc(PuglView* view, PuglReshapeFunc reshapeFunc) | |||
{ | |||
view->reshapeFunc = reshapeFunc; | |||
} | |||
void | |||
puglSetScrollFunc(PuglView* view, PuglScrollFunc scrollFunc) | |||
{ | |||
view->scrollFunc = scrollFunc; | |||
} | |||
void | |||
puglSetSpecialFunc(PuglView* view, PuglSpecialFunc specialFunc) | |||
{ | |||
view->specialFunc = specialFunc; | |||
} |
@@ -0,0 +1,117 @@ | |||
--- GIT-other/pugl/pugl/pugl_osx.m 2014-01-27 21:32:59.399032199 +0000 | |||
+++ GIT-mine/DPF/dgl/src/pugl/pugl_osx.m 2014-01-27 22:43:50.754197989 +0000 | |||
@@ -36,6 +36,7 @@ | |||
defer:(BOOL)flag; | |||
- (void) setPuglview:(PuglView*)view; | |||
- (BOOL) windowShouldClose:(id)sender; | |||
+- (BOOL) canBecomeKeyWindow:(id)sender; | |||
@end | |||
@implementation PuglWindow | |||
@@ -70,9 +71,14 @@ | |||
return YES; | |||
} | |||
+- (BOOL) canBecomeKeyWindow:(id)sender | |||
+{ | |||
+ return NO; | |||
+} | |||
+ | |||
@end | |||
-static void | |||
+void | |||
puglDisplay(PuglView* view) | |||
{ | |||
if (view->displayFunc) { | |||
@@ -95,13 +101,16 @@ | |||
depthBits:(int)numDepthBits; | |||
- (void) reshape; | |||
- (void) drawRect:(NSRect)rect; | |||
+- (void) mouseEntered:(NSEvent*)event; | |||
+- (void) mouseExited:(NSEvent*)event; | |||
- (void) mouseMoved:(NSEvent*)event; | |||
- (void) mouseDragged:(NSEvent*)event; | |||
+- (void) rightMouseDragged:(NSEvent*)event; | |||
- (void) mouseDown:(NSEvent*)event; | |||
- (void) mouseUp:(NSEvent*)event; | |||
-- (void) rightMouseDragged:(NSEvent*)event; | |||
- (void) rightMouseDown:(NSEvent*)event; | |||
- (void) rightMouseUp:(NSEvent*)event; | |||
+- (void) scrollWheel:(NSEvent*)event; | |||
- (void) keyDown:(NSEvent*)event; | |||
- (void) keyUp:(NSEvent*)event; | |||
- (void) flagsChanged:(NSEvent*)event; | |||
@@ -170,7 +179,7 @@ | |||
- (void) drawRect:(NSRect)rect | |||
{ | |||
- display(puglview); | |||
+ puglDisplay(puglview); | |||
glFlush(); | |||
glSwapAPPLE(); | |||
} | |||
@@ -182,6 +191,10 @@ | |||
view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); | |||
+ double ts = [ev timestamp] * 1000.0; | |||
+ ts = (uint32)ts % 500000; //ridiculously large vals won't fit | |||
+ view->event_timestamp_ms = ts; | |||
+ | |||
unsigned mods = 0; | |||
mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; | |||
mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; | |||
@@ -332,6 +345,7 @@ | |||
struct PuglInternalsImpl { | |||
PuglOpenGLView* glview; | |||
id window; | |||
+ bool isEmbed; | |||
}; | |||
PuglView* | |||
@@ -367,6 +381,7 @@ | |||
impl->glview = [PuglOpenGLView new]; | |||
impl->window = window; | |||
+ impl->isEmbed = (parent != 0); | |||
impl->glview->puglview = view; | |||
[window setContentView:impl->glview]; | |||
@@ -396,6 +411,36 @@ | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
+ if (! view->impl->isEmbed) | |||
+ { | |||
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | |||
+ NSEvent* event; | |||
+ | |||
+ static const NSUInteger eventMask = (NSLeftMouseDownMask | NSLeftMouseUpMask | | |||
+ NSRightMouseDownMask | NSRightMouseUpMask | | |||
+ NSMouseMovedMask | | |||
+ NSLeftMouseDraggedMask | NSRightMouseDraggedMask | | |||
+ NSMouseEnteredMask | NSMouseExitedMask | | |||
+ NSKeyDownMask | NSKeyUpMask | | |||
+ NSFlagsChangedMask | | |||
+ NSCursorUpdateMask | NSScrollWheelMask); | |||
+ | |||
+ for (;;) { | |||
+ event = [view->impl->window | |||
+ nextEventMatchingMask:eventMask | |||
+ untilDate:[NSDate distantPast] | |||
+ inMode:NSEventTrackingRunLoopMode | |||
+ dequeue:YES]; | |||
+ | |||
+ if (event == nil) | |||
+ break; | |||
+ | |||
+ [view->impl->window sendEvent: event]; | |||
+ } | |||
+ | |||
+ [pool release]; | |||
+ } | |||
+ | |||
[view->impl->glview setNeedsDisplay: YES]; | |||
return PUGL_SUCCESS; |
@@ -0,0 +1,459 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file pugl_osx.m OSX/Cocoa Pugl Implementation. | |||
*/ | |||
#include <stdlib.h> | |||
#import <Cocoa/Cocoa.h> | |||
#include "pugl_internal.h" | |||
@interface PuglWindow : NSWindow | |||
{ | |||
@public | |||
PuglView* puglview; | |||
} | |||
- (id) initWithContentRect:(NSRect)contentRect | |||
styleMask:(unsigned int)aStyle | |||
backing:(NSBackingStoreType)bufferingType | |||
defer:(BOOL)flag; | |||
- (void) setPuglview:(PuglView*)view; | |||
- (BOOL) windowShouldClose:(id)sender; | |||
- (BOOL) canBecomeKeyWindow:(id)sender; | |||
@end | |||
@implementation PuglWindow | |||
- (id)initWithContentRect:(NSRect)contentRect | |||
styleMask:(unsigned int)aStyle | |||
backing:(NSBackingStoreType)bufferingType | |||
defer:(BOOL)flag | |||
{ | |||
NSWindow* result = [super initWithContentRect:contentRect | |||
styleMask:(NSClosableWindowMask | | |||
NSTitledWindowMask | | |||
NSResizableWindowMask) | |||
backing:NSBackingStoreBuffered defer:NO]; | |||
[result setAcceptsMouseMovedEvents:YES]; | |||
[result setLevel: CGShieldingWindowLevel() + 1]; | |||
return result; | |||
} | |||
- (void)setPuglview:(PuglView*)view | |||
{ | |||
puglview = view; | |||
[self setContentSize:NSMakeSize(view->width, view->height) ]; | |||
} | |||
- (BOOL)windowShouldClose:(id)sender | |||
{ | |||
if (puglview->closeFunc) | |||
puglview->closeFunc(puglview); | |||
return YES; | |||
} | |||
- (BOOL) canBecomeKeyWindow:(id)sender | |||
{ | |||
return NO; | |||
} | |||
@end | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
} | |||
@interface PuglOpenGLView : NSOpenGLView | |||
{ | |||
int colorBits; | |||
int depthBits; | |||
@public | |||
PuglView* puglview; | |||
NSTrackingArea* trackingArea; | |||
} | |||
- (id) initWithFrame:(NSRect)frame | |||
colorBits:(int)numColorBits | |||
depthBits:(int)numDepthBits; | |||
- (void) reshape; | |||
- (void) drawRect:(NSRect)rect; | |||
- (void) mouseEntered:(NSEvent*)event; | |||
- (void) mouseExited:(NSEvent*)event; | |||
- (void) mouseMoved:(NSEvent*)event; | |||
- (void) mouseDragged:(NSEvent*)event; | |||
- (void) rightMouseDragged:(NSEvent*)event; | |||
- (void) mouseDown:(NSEvent*)event; | |||
- (void) mouseUp:(NSEvent*)event; | |||
- (void) rightMouseDown:(NSEvent*)event; | |||
- (void) rightMouseUp:(NSEvent*)event; | |||
- (void) scrollWheel:(NSEvent*)event; | |||
- (void) keyDown:(NSEvent*)event; | |||
- (void) keyUp:(NSEvent*)event; | |||
- (void) flagsChanged:(NSEvent*)event; | |||
@end | |||
@implementation PuglOpenGLView | |||
- (id) initWithFrame:(NSRect)frame | |||
colorBits:(int)numColorBits | |||
depthBits:(int)numDepthBits | |||
{ | |||
colorBits = numColorBits; | |||
depthBits = numDepthBits; | |||
NSOpenGLPixelFormatAttribute pixelAttribs[16] = { | |||
NSOpenGLPFADoubleBuffer, | |||
NSOpenGLPFAAccelerated, | |||
NSOpenGLPFAColorSize, | |||
colorBits, | |||
NSOpenGLPFADepthSize, | |||
depthBits, | |||
0 | |||
}; | |||
NSOpenGLPixelFormat* pixelFormat = [[NSOpenGLPixelFormat alloc] | |||
initWithAttributes:pixelAttribs]; | |||
if (pixelFormat) { | |||
self = [super initWithFrame:frame pixelFormat:pixelFormat]; | |||
[pixelFormat release]; | |||
if (self) { | |||
[[self openGLContext] makeCurrentContext]; | |||
[self reshape]; | |||
} | |||
} else { | |||
self = nil; | |||
} | |||
return self; | |||
} | |||
- (void) reshape | |||
{ | |||
[[self openGLContext] update]; | |||
NSRect bounds = [self bounds]; | |||
int width = bounds.size.width; | |||
int height = bounds.size.height; | |||
if (puglview) { | |||
/* NOTE: Apparently reshape gets called when the GC gets around to | |||
deleting the view (?), so we must have reset puglview to NULL when | |||
this comes around. | |||
*/ | |||
if (puglview->reshapeFunc) { | |||
puglview->reshapeFunc(puglview, width, height); | |||
} else { | |||
puglDefaultReshape(puglview, width, height); | |||
} | |||
puglview->width = width; | |||
puglview->height = height; | |||
} | |||
} | |||
- (void) drawRect:(NSRect)rect | |||
{ | |||
puglDisplay(puglview); | |||
glFlush(); | |||
glSwapAPPLE(); | |||
} | |||
static unsigned | |||
getModifiers(PuglView* view, NSEvent* ev) | |||
{ | |||
const unsigned modifierFlags = [ev modifierFlags]; | |||
view->event_timestamp_ms = fmod([ev timestamp] * 1000.0, UINT32_MAX); | |||
double ts = [ev timestamp] * 1000.0; | |||
ts = (uint32)ts % 500000; //ridiculously large vals won't fit | |||
view->event_timestamp_ms = ts; | |||
unsigned mods = 0; | |||
mods |= (modifierFlags & NSShiftKeyMask) ? PUGL_MOD_SHIFT : 0; | |||
mods |= (modifierFlags & NSControlKeyMask) ? PUGL_MOD_CTRL : 0; | |||
mods |= (modifierFlags & NSAlternateKeyMask) ? PUGL_MOD_ALT : 0; | |||
mods |= (modifierFlags & NSCommandKeyMask) ? PUGL_MOD_SUPER : 0; | |||
return mods; | |||
} | |||
-(void)updateTrackingAreas | |||
{ | |||
if (trackingArea != nil) { | |||
[self removeTrackingArea:trackingArea]; | |||
[trackingArea release]; | |||
} | |||
const int opts = (NSTrackingMouseEnteredAndExited | | |||
NSTrackingMouseMoved | | |||
NSTrackingActiveAlways); | |||
trackingArea = [ [NSTrackingArea alloc] initWithRect:[self bounds] | |||
options:opts | |||
owner:self | |||
userInfo:nil]; | |||
[self addTrackingArea:trackingArea]; | |||
} | |||
- (void)mouseEntered:(NSEvent*)theEvent | |||
{ | |||
[self updateTrackingAreas]; | |||
} | |||
- (void)mouseExited:(NSEvent*)theEvent | |||
{ | |||
} | |||
- (void) mouseMoved:(NSEvent*)event | |||
{ | |||
if (puglview->motionFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) mouseDragged:(NSEvent*)event | |||
{ | |||
if (puglview->motionFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) rightMouseDragged:(NSEvent*)event | |||
{ | |||
if (puglview->motionFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->motionFunc(puglview, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) mouseDown:(NSEvent*)event | |||
{ | |||
if (puglview->mouseFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->mouseFunc(puglview, 1, true, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) mouseUp:(NSEvent*)event | |||
{ | |||
if (puglview->mouseFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->mouseFunc(puglview, 1, false, loc.x, puglview->height - loc.y); | |||
} | |||
[self updateTrackingAreas]; | |||
} | |||
- (void) rightMouseDown:(NSEvent*)event | |||
{ | |||
if (puglview->mouseFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->mouseFunc(puglview, 3, true, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) rightMouseUp:(NSEvent*)event | |||
{ | |||
if (puglview->mouseFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->mouseFunc(puglview, 3, false, loc.x, puglview->height - loc.y); | |||
} | |||
} | |||
- (void) scrollWheel:(NSEvent*)event | |||
{ | |||
if (puglview->scrollFunc) { | |||
NSPoint loc = [event locationInWindow]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->scrollFunc(puglview, | |||
loc.x, puglview->height - loc.y, | |||
[event deltaX], [event deltaY]); | |||
} | |||
[self updateTrackingAreas]; | |||
} | |||
- (void) keyDown:(NSEvent*)event | |||
{ | |||
if (puglview->keyboardFunc && !(puglview->ignoreKeyRepeat && [event isARepeat])) { | |||
NSString* chars = [event characters]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->keyboardFunc(puglview, true, [chars characterAtIndex:0]); | |||
} | |||
} | |||
- (void) keyUp:(NSEvent*)event | |||
{ | |||
if (puglview->keyboardFunc) { | |||
NSString* chars = [event characters]; | |||
puglview->mods = getModifiers(puglview, event); | |||
puglview->keyboardFunc(puglview, false, [chars characterAtIndex:0]); | |||
} | |||
} | |||
- (void) flagsChanged:(NSEvent*)event | |||
{ | |||
if (puglview->specialFunc) { | |||
const unsigned mods = getModifiers(puglview, event); | |||
if ((mods & PUGL_MOD_SHIFT) != (puglview->mods & PUGL_MOD_SHIFT)) { | |||
puglview->specialFunc(puglview, mods & PUGL_MOD_SHIFT, PUGL_KEY_SHIFT); | |||
} else if ((mods & PUGL_MOD_CTRL) != (puglview->mods & PUGL_MOD_CTRL)) { | |||
puglview->specialFunc(puglview, mods & PUGL_MOD_CTRL, PUGL_KEY_CTRL); | |||
} else if ((mods & PUGL_MOD_ALT) != (puglview->mods & PUGL_MOD_ALT)) { | |||
puglview->specialFunc(puglview, mods & PUGL_MOD_ALT, PUGL_KEY_ALT); | |||
} else if ((mods & PUGL_MOD_SUPER) != (puglview->mods & PUGL_MOD_SUPER)) { | |||
puglview->specialFunc(puglview, mods & PUGL_MOD_SUPER, PUGL_KEY_SUPER); | |||
} | |||
puglview->mods = mods; | |||
} | |||
} | |||
@end | |||
struct PuglInternalsImpl { | |||
PuglOpenGLView* glview; | |||
id window; | |||
bool isEmbed; | |||
}; | |||
PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
if (!view || !impl) { | |||
return NULL; | |||
} | |||
view->impl = impl; | |||
view->width = width; | |||
view->height = height; | |||
[NSAutoreleasePool new]; | |||
[NSApplication sharedApplication]; | |||
NSString* titleString = [[NSString alloc] | |||
initWithBytes:title | |||
length:strlen(title) | |||
encoding:NSUTF8StringEncoding]; | |||
id window = [[PuglWindow new]retain]; | |||
[window setPuglview:view]; | |||
[window setTitle:titleString]; | |||
impl->glview = [PuglOpenGLView new]; | |||
impl->window = window; | |||
impl->isEmbed = (parent != 0); | |||
impl->glview->puglview = view; | |||
[window setContentView:impl->glview]; | |||
[NSApp activateIgnoringOtherApps:YES]; | |||
[window makeFirstResponder:impl->glview]; | |||
[window makeKeyAndOrderFront:window]; | |||
if (! visible) { | |||
[window setIsVisible:NO]; | |||
} | |||
return view; | |||
} | |||
void | |||
puglDestroy(PuglView* view) | |||
{ | |||
view->impl->glview->puglview = NULL; | |||
[view->impl->window close]; | |||
[view->impl->glview release]; | |||
[view->impl->window release]; | |||
free(view->impl); | |||
free(view); | |||
} | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
if (! view->impl->isEmbed) | |||
{ | |||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; | |||
NSEvent* event; | |||
static const NSUInteger eventMask = (NSLeftMouseDownMask | NSLeftMouseUpMask | | |||
NSRightMouseDownMask | NSRightMouseUpMask | | |||
NSMouseMovedMask | | |||
NSLeftMouseDraggedMask | NSRightMouseDraggedMask | | |||
NSMouseEnteredMask | NSMouseExitedMask | | |||
NSKeyDownMask | NSKeyUpMask | | |||
NSFlagsChangedMask | | |||
NSCursorUpdateMask | NSScrollWheelMask); | |||
for (;;) { | |||
event = [view->impl->window | |||
nextEventMatchingMask:eventMask | |||
untilDate:[NSDate distantPast] | |||
inMode:NSEventTrackingRunLoopMode | |||
dequeue:YES]; | |||
if (event == nil) | |||
break; | |||
[view->impl->window sendEvent: event]; | |||
} | |||
[pool release]; | |||
} | |||
[view->impl->glview setNeedsDisplay: YES]; | |||
return PUGL_SUCCESS; | |||
} | |||
void | |||
puglPostRedisplay(PuglView* view) | |||
{ | |||
view->redisplay = true; | |||
} | |||
PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view) | |||
{ | |||
return (PuglNativeWindow)view->impl->glview; | |||
} |
@@ -23,7 +23,15 @@ | |||
#include "pugl.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
void puglImplFocus(PuglView* view); | |||
void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height); | |||
void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height, bool forced); | |||
void puglImplSetTitle(PuglView* view, const char* title); | |||
void puglImplSetVisible(PuglView* view, bool yesNo); | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif |
@@ -25,20 +25,27 @@ | |||
void puglImplFocus(PuglView* view) | |||
{ | |||
id window = view->impl->window; | |||
// TODO | |||
[NSApp activateIgnoringOtherApps:YES]; | |||
[window makeKeyAndOrderFront:window]; | |||
} | |||
void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height) | |||
void puglImplSetSize(PuglView* view, unsigned int width, unsigned int height, bool forced) | |||
{ | |||
//id window = view->impl->window; | |||
id window = view->impl->window; | |||
// TODO | |||
//NSRect frame = [window frame]; | |||
//frame.size.width = width; | |||
//frame.size.height = height; | |||
NSRect frame = [window frame]; | |||
frame.origin.y -= height - frame.size.height; | |||
frame.size.width = width; | |||
frame.size.height = height+20; | |||
// display:NO ? | |||
//[window setFrame:frame display:YES animate:NO]; | |||
// if (forced) { | |||
// [window setFrame:frame]; | |||
// } else { | |||
[window setFrame:frame display:YES animate:NO]; | |||
// } | |||
} | |||
void puglImplSetTitle(PuglView* view, const char* title) |
@@ -0,0 +1,387 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file pugl_win.cpp Windows/WGL Pugl Implementation. | |||
*/ | |||
#include <windows.h> | |||
#include <windowsx.h> | |||
#include <GL/gl.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include "pugl_internal.h" | |||
#ifndef WM_MOUSEWHEEL | |||
# define WM_MOUSEWHEEL 0x020A | |||
#endif | |||
#ifndef WM_MOUSEHWHEEL | |||
# define WM_MOUSEHWHEEL 0x020E | |||
#endif | |||
#ifndef WHEEL_DELTA | |||
# define WHEEL_DELTA 120 | |||
#endif | |||
const int LOCAL_CLOSE_MSG = WM_USER + 50; | |||
struct PuglInternalsImpl { | |||
HWND hwnd; | |||
HDC hdc; | |||
HGLRC hglrc; | |||
WNDCLASS wc; | |||
}; | |||
LRESULT CALLBACK | |||
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); | |||
PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
if (!view || !impl) { | |||
return NULL; | |||
} | |||
view->impl = impl; | |||
view->width = width; | |||
view->height = height; | |||
// FIXME: This is nasty, and pugl should not have static anything. | |||
// Should class be a parameter? Does this make sense on other platforms? | |||
static int wc_count = 0; | |||
char classNameBuf[256]; | |||
_snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++); | |||
impl->wc.style = CS_OWNDC; | |||
impl->wc.lpfnWndProc = wndProc; | |||
impl->wc.cbClsExtra = 0; | |||
impl->wc.cbWndExtra = 0; | |||
impl->wc.hInstance = 0; | |||
impl->wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); | |||
impl->wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |||
impl->wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); | |||
impl->wc.lpszMenuName = NULL; | |||
impl->wc.lpszClassName = classNameBuf; | |||
RegisterClass(&impl->wc); | |||
int winFlags = WS_POPUPWINDOW | WS_CAPTION; | |||
if (resizable) { | |||
winFlags |= WS_SIZEBOX; | |||
} | |||
// Adjust the overall window size to accomodate our requested client size | |||
RECT wr = { 0, 0, width, height }; | |||
AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); | |||
impl->hwnd = CreateWindowEx( | |||
WS_EX_TOPMOST, | |||
classNameBuf, title, | |||
(visible ? WS_VISIBLE : 0) | (parent ? WS_CHILD : winFlags), | |||
0, 0, wr.right-wr.left, wr.bottom-wr.top, | |||
(HWND)parent, NULL, NULL, NULL); | |||
if (!impl->hwnd) { | |||
free(impl); | |||
free(view); | |||
return NULL; | |||
} | |||
#ifdef _WIN64 | |||
SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); | |||
#else | |||
SetWindowLongPtr(impl->hwnd, GWL_USERDATA, (LONG)view); | |||
#endif | |||
impl->hdc = GetDC(impl->hwnd); | |||
PIXELFORMATDESCRIPTOR pfd; | |||
ZeroMemory(&pfd, sizeof(pfd)); | |||
pfd.nSize = sizeof(pfd); | |||
pfd.nVersion = 1; | |||
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; | |||
pfd.iPixelType = PFD_TYPE_RGBA; | |||
pfd.cColorBits = 24; | |||
pfd.cDepthBits = 16; | |||
pfd.iLayerType = PFD_MAIN_PLANE; | |||
int format = ChoosePixelFormat(impl->hdc, &pfd); | |||
SetPixelFormat(impl->hdc, format, &pfd); | |||
impl->hglrc = wglCreateContext(impl->hdc); | |||
wglMakeCurrent(impl->hdc, impl->hglrc); | |||
view->width = width; | |||
view->height = height; | |||
return view; | |||
} | |||
void | |||
puglDestroy(PuglView* view) | |||
{ | |||
wglMakeCurrent(NULL, NULL); | |||
wglDeleteContext(view->impl->hglrc); | |||
ReleaseDC(view->impl->hwnd, view->impl->hdc); | |||
DestroyWindow(view->impl->hwnd); | |||
UnregisterClass(view->impl->wc.lpszClassName, NULL); | |||
free(view->impl); | |||
free(view); | |||
} | |||
void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
if (view->reshapeFunc) { | |||
view->reshapeFunc(view, width, height); | |||
} else { | |||
puglDefaultReshape(view, width, height); | |||
} | |||
view->width = width; | |||
view->height = height; | |||
} | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
glLoadIdentity(); | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
glFlush(); | |||
SwapBuffers(view->impl->hdc); | |||
view->redisplay = false; | |||
} | |||
static PuglKey | |||
keySymToSpecial(int sym) | |||
{ | |||
switch (sym) { | |||
case VK_F1: return PUGL_KEY_F1; | |||
case VK_F2: return PUGL_KEY_F2; | |||
case VK_F3: return PUGL_KEY_F3; | |||
case VK_F4: return PUGL_KEY_F4; | |||
case VK_F5: return PUGL_KEY_F5; | |||
case VK_F6: return PUGL_KEY_F6; | |||
case VK_F7: return PUGL_KEY_F7; | |||
case VK_F8: return PUGL_KEY_F8; | |||
case VK_F9: return PUGL_KEY_F9; | |||
case VK_F10: return PUGL_KEY_F10; | |||
case VK_F11: return PUGL_KEY_F11; | |||
case VK_F12: return PUGL_KEY_F12; | |||
case VK_LEFT: return PUGL_KEY_LEFT; | |||
case VK_UP: return PUGL_KEY_UP; | |||
case VK_RIGHT: return PUGL_KEY_RIGHT; | |||
case VK_DOWN: return PUGL_KEY_DOWN; | |||
case VK_PRIOR: return PUGL_KEY_PAGE_UP; | |||
case VK_NEXT: return PUGL_KEY_PAGE_DOWN; | |||
case VK_HOME: return PUGL_KEY_HOME; | |||
case VK_END: return PUGL_KEY_END; | |||
case VK_INSERT: return PUGL_KEY_INSERT; | |||
case VK_SHIFT: return PUGL_KEY_SHIFT; | |||
case VK_CONTROL: return PUGL_KEY_CTRL; | |||
case VK_MENU: return PUGL_KEY_ALT; | |||
case VK_LWIN: return PUGL_KEY_SUPER; | |||
case VK_RWIN: return PUGL_KEY_SUPER; | |||
} | |||
return (PuglKey)0; | |||
} | |||
static void | |||
processMouseEvent(PuglView* view, int button, bool press, LPARAM lParam) | |||
{ | |||
view->event_timestamp_ms = GetMessageTime(); | |||
if (press) { | |||
SetCapture(view->impl->hwnd); | |||
} else { | |||
ReleaseCapture(); | |||
} | |||
if (view->mouseFunc) { | |||
view->mouseFunc(view, button, press, | |||
GET_X_LPARAM(lParam), | |||
GET_Y_LPARAM(lParam)); | |||
} | |||
} | |||
static void | |||
setModifiers(PuglView* view) | |||
{ | |||
view->mods = 0; | |||
view->mods |= (GetKeyState(VK_SHIFT) < 0) ? PUGL_MOD_SHIFT : 0; | |||
view->mods |= (GetKeyState(VK_CONTROL) < 0) ? PUGL_MOD_CTRL : 0; | |||
view->mods |= (GetKeyState(VK_MENU) < 0) ? PUGL_MOD_ALT : 0; | |||
view->mods |= (GetKeyState(VK_LWIN) < 0) ? PUGL_MOD_SUPER : 0; | |||
view->mods |= (GetKeyState(VK_RWIN) < 0) ? PUGL_MOD_SUPER : 0; | |||
} | |||
static LRESULT | |||
handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
{ | |||
PAINTSTRUCT ps; | |||
PuglKey key; | |||
setModifiers(view); | |||
switch (message) { | |||
case WM_CREATE: | |||
case WM_SHOWWINDOW: | |||
case WM_SIZE: | |||
RECT rect; | |||
GetClientRect(view->impl->hwnd, &rect); | |||
puglReshape(view, rect.right, rect.bottom); | |||
view->width = rect.right; | |||
view->height = rect.bottom; | |||
break; | |||
case WM_PAINT: | |||
BeginPaint(view->impl->hwnd, &ps); | |||
puglDisplay(view); | |||
EndPaint(view->impl->hwnd, &ps); | |||
break; | |||
case WM_MOUSEMOVE: | |||
if (view->motionFunc) { | |||
view->motionFunc(view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); | |||
} | |||
break; | |||
case WM_LBUTTONDOWN: | |||
processMouseEvent(view, 1, true, lParam); | |||
break; | |||
case WM_MBUTTONDOWN: | |||
processMouseEvent(view, 2, true, lParam); | |||
break; | |||
case WM_RBUTTONDOWN: | |||
processMouseEvent(view, 3, true, lParam); | |||
break; | |||
case WM_LBUTTONUP: | |||
processMouseEvent(view, 1, false, lParam); | |||
break; | |||
case WM_MBUTTONUP: | |||
processMouseEvent(view, 2, false, lParam); | |||
break; | |||
case WM_RBUTTONUP: | |||
processMouseEvent(view, 3, false, lParam); | |||
break; | |||
case WM_MOUSEWHEEL: | |||
if (view->scrollFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->scrollFunc( | |||
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | |||
0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); | |||
} | |||
break; | |||
case WM_MOUSEHWHEEL: | |||
if (view->scrollFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->scrollFunc( | |||
view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | |||
(int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); | |||
} | |||
break; | |||
case WM_KEYDOWN: | |||
if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | |||
break; | |||
} // else nobreak | |||
case WM_KEYUP: | |||
view->event_timestamp_ms = GetMessageTime(); | |||
if ((key = keySymToSpecial(wParam))) { | |||
if (view->specialFunc) { | |||
view->specialFunc(view, message == WM_KEYDOWN, key); | |||
} | |||
} else if (view->keyboardFunc) { | |||
view->keyboardFunc(view, message == WM_KEYDOWN, wParam); | |||
} | |||
break; | |||
case WM_QUIT: | |||
case LOCAL_CLOSE_MSG: | |||
if (view->closeFunc) { | |||
view->closeFunc(view); | |||
} | |||
break; | |||
default: | |||
return DefWindowProc( | |||
view->impl->hwnd, message, wParam, lParam); | |||
} | |||
return 0; | |||
} | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
MSG msg; | |||
while (PeekMessage(&msg, view->impl->hwnd, 0, 0, PM_REMOVE)) { | |||
handleMessage(view, msg.message, msg.wParam, msg.lParam); | |||
} | |||
if (view->redisplay) { | |||
InvalidateRect(view->impl->hwnd, NULL, FALSE); | |||
} | |||
return PUGL_SUCCESS; | |||
} | |||
LRESULT CALLBACK | |||
wndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) | |||
{ | |||
#ifdef _WIN64 | |||
PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWLP_USERDATA); | |||
#else | |||
PuglView* view = (PuglView*)GetWindowLongPtr(hwnd, GWL_USERDATA); | |||
#endif | |||
switch (message) { | |||
case WM_CREATE: | |||
PostMessage(hwnd, WM_SHOWWINDOW, TRUE, 0); | |||
return 0; | |||
case WM_CLOSE: | |||
PostMessage(hwnd, LOCAL_CLOSE_MSG, wParam, lParam); | |||
return 0; | |||
case WM_DESTROY: | |||
return 0; | |||
default: | |||
if (view) { | |||
return handleMessage(view, message, wParam, lParam); | |||
} else { | |||
return DefWindowProc(hwnd, message, wParam, lParam); | |||
} | |||
} | |||
} | |||
void | |||
puglPostRedisplay(PuglView* view) | |||
{ | |||
view->redisplay = true; | |||
} | |||
PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view) | |||
{ | |||
return (PuglNativeWindow)view->impl->hwnd; | |||
} |
@@ -0,0 +1,397 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file pugl_x11.c X11 Pugl Implementation. | |||
*/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <GL/gl.h> | |||
#include <GL/glx.h> | |||
#include <X11/Xatom.h> | |||
#include <X11/Xlib.h> | |||
#include <X11/keysym.h> | |||
#include "pugl_internal.h" | |||
struct PuglInternalsImpl { | |||
Display* display; | |||
int screen; | |||
Window win; | |||
GLXContext ctx; | |||
Bool doubleBuffered; | |||
}; | |||
/** | |||
Attributes for single-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
static int attrListSgl[] = { | |||
GLX_RGBA, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
None | |||
}; | |||
/** | |||
Attributes for double-buffered RGBA with at least | |||
4 bits per color and a 16 bit depth buffer. | |||
*/ | |||
static int attrListDbl[] = { | |||
GLX_RGBA, GLX_DOUBLEBUFFER, | |||
GLX_RED_SIZE, 4, | |||
GLX_GREEN_SIZE, 4, | |||
GLX_BLUE_SIZE, 4, | |||
GLX_DEPTH_SIZE, 16, | |||
None | |||
}; | |||
PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
if (!view || !impl) { | |||
return NULL; | |||
} | |||
view->impl = impl; | |||
view->width = width; | |||
view->height = height; | |||
impl->display = XOpenDisplay(0); | |||
impl->screen = DefaultScreen(impl->display); | |||
XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||
if (!vi) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
impl->doubleBuffered = False; | |||
PUGL_LOG("No double buffering available\n"); | |||
} else { | |||
impl->doubleBuffered = True; | |||
PUGL_LOG("Double buffered rendering enabled\n"); | |||
} | |||
int glxMajor, glxMinor; | |||
glXQueryVersion(impl->display, &glxMajor, &glxMinor); | |||
PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
Window xParent = parent | |||
? (Window)parent | |||
: RootWindow(impl->display, impl->screen); | |||
Colormap cmap = XCreateColormap( | |||
impl->display, xParent, vi->visual, AllocNone); | |||
XSetWindowAttributes attr; | |||
memset(&attr, 0, sizeof(XSetWindowAttributes)); | |||
attr.colormap = cmap; | |||
attr.border_pixel = 0; | |||
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | |||
| ButtonPressMask | ButtonReleaseMask | |||
#ifdef XKEYFOCUSGRAB | |||
| EnterWindowMask | |||
#endif | |||
| PointerMotionMask | StructureNotifyMask; | |||
impl->win = XCreateWindow( | |||
impl->display, xParent, | |||
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | |||
CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
XSizeHints sizeHints; | |||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||
if (!resizable) { | |||
sizeHints.flags = PMinSize|PMaxSize; | |||
sizeHints.min_width = width; | |||
sizeHints.min_height = height; | |||
sizeHints.max_width = width; | |||
sizeHints.max_height = height; | |||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||
} | |||
if (title) { | |||
XStoreName(impl->display, impl->win, title); | |||
} | |||
if (!parent) { | |||
Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | |||
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | |||
} | |||
if (visible) { | |||
XMapRaised(impl->display, impl->win); | |||
} | |||
if (glXIsDirect(impl->display, impl->ctx)) { | |||
PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||
} else { | |||
PUGL_LOG("No DRI available\n"); | |||
} | |||
XFree(vi); | |||
return view; | |||
} | |||
void | |||
puglDestroy(PuglView* view) | |||
{ | |||
if (!view) { | |||
return; | |||
} | |||
glXDestroyContext(view->impl->display, view->impl->ctx); | |||
XDestroyWindow(view->impl->display, view->impl->win); | |||
XCloseDisplay(view->impl->display); | |||
free(view->impl); | |||
free(view); | |||
} | |||
void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
if (view->reshapeFunc) { | |||
view->reshapeFunc(view, width, height); | |||
} else { | |||
puglDefaultReshape(view, width, height); | |||
} | |||
view->width = width; | |||
view->height = height; | |||
} | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |||
glLoadIdentity(); | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
glFlush(); | |||
if (view->impl->doubleBuffered) { | |||
glXSwapBuffers(view->impl->display, view->impl->win); | |||
} | |||
view->redisplay = false; | |||
} | |||
static PuglKey | |||
keySymToSpecial(KeySym sym) | |||
{ | |||
switch (sym) { | |||
case XK_F1: return PUGL_KEY_F1; | |||
case XK_F2: return PUGL_KEY_F2; | |||
case XK_F3: return PUGL_KEY_F3; | |||
case XK_F4: return PUGL_KEY_F4; | |||
case XK_F5: return PUGL_KEY_F5; | |||
case XK_F6: return PUGL_KEY_F6; | |||
case XK_F7: return PUGL_KEY_F7; | |||
case XK_F8: return PUGL_KEY_F8; | |||
case XK_F9: return PUGL_KEY_F9; | |||
case XK_F10: return PUGL_KEY_F10; | |||
case XK_F11: return PUGL_KEY_F11; | |||
case XK_F12: return PUGL_KEY_F12; | |||
case XK_Left: return PUGL_KEY_LEFT; | |||
case XK_Up: return PUGL_KEY_UP; | |||
case XK_Right: return PUGL_KEY_RIGHT; | |||
case XK_Down: return PUGL_KEY_DOWN; | |||
case XK_Page_Up: return PUGL_KEY_PAGE_UP; | |||
case XK_Page_Down: return PUGL_KEY_PAGE_DOWN; | |||
case XK_Home: return PUGL_KEY_HOME; | |||
case XK_End: return PUGL_KEY_END; | |||
case XK_Insert: return PUGL_KEY_INSERT; | |||
case XK_Shift_L: return PUGL_KEY_SHIFT; | |||
case XK_Shift_R: return PUGL_KEY_SHIFT; | |||
case XK_Control_L: return PUGL_KEY_CTRL; | |||
case XK_Control_R: return PUGL_KEY_CTRL; | |||
case XK_Alt_L: return PUGL_KEY_ALT; | |||
case XK_Alt_R: return PUGL_KEY_ALT; | |||
case XK_Super_L: return PUGL_KEY_SUPER; | |||
case XK_Super_R: return PUGL_KEY_SUPER; | |||
} | |||
return (PuglKey)0; | |||
} | |||
static void | |||
setModifiers(PuglView* view, unsigned xstate, unsigned xtime) | |||
{ | |||
view->event_timestamp_ms = xtime; | |||
view->mods = 0; | |||
view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; | |||
view->mods |= (xstate & ControlMask) ? PUGL_MOD_CTRL : 0; | |||
view->mods |= (xstate & Mod1Mask) ? PUGL_MOD_ALT : 0; | |||
view->mods |= (xstate & Mod4Mask) ? PUGL_MOD_SUPER : 0; | |||
} | |||
static void | |||
dispatchKey(PuglView* view, XEvent* event, bool press) | |||
{ | |||
KeySym sym; | |||
char str[5]; | |||
const int n = XLookupString(&event->xkey, str, 4, &sym, NULL); | |||
if (n == 0) { | |||
return; | |||
} else if (n > 1) { | |||
fprintf(stderr, "warning: Unsupported multi-byte key %X\n", (int)sym); | |||
return; | |||
} | |||
const PuglKey special = keySymToSpecial(sym); | |||
if (special && view->specialFunc) { | |||
view->specialFunc(view, press, special); | |||
} else if (!special && view->keyboardFunc) { | |||
view->keyboardFunc(view, press, str[0]); | |||
} | |||
} | |||
PuglStatus | |||
puglProcessEvents(PuglView* view) | |||
{ | |||
XEvent event; | |||
while (XPending(view->impl->display) > 0) { | |||
XNextEvent(view->impl->display, &event); | |||
switch (event.type) { | |||
case MapNotify: | |||
puglReshape(view, view->width, view->height); | |||
break; | |||
case ConfigureNotify: | |||
if ((event.xconfigure.width != view->width) || | |||
(event.xconfigure.height != view->height)) { | |||
puglReshape(view, | |||
event.xconfigure.width, | |||
event.xconfigure.height); | |||
} | |||
break; | |||
case Expose: | |||
if (event.xexpose.count != 0) { | |||
break; | |||
} | |||
puglDisplay(view); | |||
break; | |||
case MotionNotify: | |||
setModifiers(view, event.xmotion.state, event.xmotion.time); | |||
if (view->motionFunc) { | |||
view->motionFunc(view, event.xmotion.x, event.xmotion.y); | |||
} | |||
break; | |||
case ButtonPress: | |||
setModifiers(view, event.xbutton.state, event.xbutton.time); | |||
if (event.xbutton.button >= 4 && event.xbutton.button <= 7) { | |||
if (view->scrollFunc) { | |||
float dx = 0, dy = 0; | |||
switch (event.xbutton.button) { | |||
case 4: dy = 1.0f; break; | |||
case 5: dy = -1.0f; break; | |||
case 6: dx = -1.0f; break; | |||
case 7: dx = 1.0f; break; | |||
} | |||
view->scrollFunc(view, | |||
event.xbutton.x, event.xbutton.y, | |||
dx, dy); | |||
} | |||
break; | |||
} | |||
// nobreak | |||
case ButtonRelease: | |||
setModifiers(view, event.xbutton.state, event.xbutton.time); | |||
if (view->mouseFunc && | |||
(event.xbutton.button < 4 || event.xbutton.button > 7)) { | |||
view->mouseFunc(view, | |||
event.xbutton.button, event.type == ButtonPress, | |||
event.xbutton.x, event.xbutton.y); | |||
} | |||
break; | |||
case KeyPress: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
dispatchKey(view, &event, true); | |||
break; | |||
case KeyRelease: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
if (view->ignoreKeyRepeat && | |||
XEventsQueued(view->impl->display, QueuedAfterReading)) { | |||
XEvent next; | |||
XPeekEvent(view->impl->display, &next); | |||
if (next.type == KeyPress && | |||
next.xkey.time == event.xkey.time && | |||
next.xkey.keycode == event.xkey.keycode) { | |||
XNextEvent(view->impl->display, &event); | |||
break; | |||
} | |||
} | |||
dispatchKey(view, &event, false); | |||
break; | |||
case ClientMessage: | |||
if (!strcmp(XGetAtomName(view->impl->display, | |||
event.xclient.message_type), | |||
"WM_PROTOCOLS")) { | |||
if (view->closeFunc) { | |||
view->closeFunc(view); | |||
} | |||
} | |||
break; | |||
#ifdef PUGL_GRAB_FOCUS | |||
case EnterNotify: | |||
XSetInputFocus(view->impl->display, | |||
view->impl->win, | |||
RevertToPointerRoot, | |||
CurrentTime); | |||
break; | |||
#endif | |||
default: | |||
break; | |||
} | |||
} | |||
if (view->redisplay) { | |||
puglDisplay(view); | |||
} | |||
return PUGL_SUCCESS; | |||
} | |||
void | |||
puglPostRedisplay(PuglView* view) | |||
{ | |||
view->redisplay = true; | |||
} | |||
PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view) | |||
{ | |||
return view->impl->win; | |||
} |
@@ -139,12 +139,36 @@ struct MidiEvent { | |||
struct TimePos { | |||
bool playing; | |||
uint64_t frame; | |||
double bpm; | |||
struct BeatBarTick { | |||
bool valid; | |||
int32_t bar; /*!< current bar */ | |||
int32_t beat; /*!< current beat-within-bar */ | |||
int32_t tick; /*!< current tick-within-beat */ | |||
double barStartTick; | |||
float beatsPerBar; /*!< time signature "numerator" */ | |||
float beatType; /*!< time signature "denominator" */ | |||
double ticksPerBeat; | |||
double beatsPerMinute; | |||
BeatBarTick() noexcept | |||
: valid(false), | |||
bar(0), | |||
beat(0), | |||
tick(0), | |||
barStartTick(0.0), | |||
beatsPerBar(0.0f), | |||
beatType(0.0f), | |||
ticksPerBeat(0.0), | |||
beatsPerMinute(0.0) {} | |||
} bbt; | |||
TimePos() noexcept | |||
: playing(false), | |||
frame(0), | |||
bpm(120.0) {} | |||
frame(0) {} | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -19,7 +19,7 @@ | |||
#include "DistrhoUtils.hpp" | |||
#include "dgl/Widget.hpp" | |||
#include "../dgl/Widget.hpp" | |||
START_NAMESPACE_DISTRHO | |||
@@ -477,7 +477,7 @@ public: | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z') | |||
fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff); | |||
fBuffer[i] += kCharDiff; | |||
} | |||
} | |||
@@ -491,7 +491,7 @@ public: | |||
for (size_t i=0; i < fBufferLen; ++i) | |||
{ | |||
if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z') | |||
fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff); | |||
fBuffer[i] -= kCharDiff; | |||
} | |||
} | |||
@@ -89,8 +89,10 @@ | |||
#endif | |||
#ifndef PROPER_CPP11_SUPPORT | |||
# ifndef __clang__ | |||
# define noexcept throw() | |||
# endif | |||
# define override | |||
# define noexcept throw() | |||
# define nullptr (0) | |||
#endif | |||
@@ -279,14 +279,10 @@ public: | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
void setTimePos(const bool playing, const uint64_t frame, const double bpm) | |||
void setTimePos(const TimePos& timePos) | |||
{ | |||
if (fData != nullptr) | |||
{ | |||
fData->timePos.playing = playing; | |||
fData->timePos.frame = frame; | |||
fData->timePos.bpm = bpm; | |||
} | |||
std::memcpy(&fData->timePos, &timePos, sizeof(TimePos)); | |||
} | |||
#endif | |||
@@ -38,7 +38,7 @@ | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# warning LV2 State still TODO | |||
# warning LV2 State still TODO (working but needs final testing) | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
# warning LV2 TimePos still TODO | |||
@@ -60,6 +60,9 @@ public: | |||
: fPortControls(nullptr), | |||
fLastControlValues(nullptr), | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
fLastTimeSpeed(0.0f), | |||
# endif | |||
fURIDs(uridMap), | |||
#endif | |||
fUridMap(uridMap), | |||
@@ -79,9 +82,8 @@ public: | |||
fPortAudioOuts = nullptr; | |||
#endif | |||
if (const uint32_t count = fPlugin.getParameterCount()) | |||
{ | |||
const uint32_t count(fPlugin.getParameterCount()); | |||
fPortControls = new float*[count]; | |||
fLastControlValues = new float[count]; | |||
@@ -91,6 +93,11 @@ public: | |||
fLastControlValues[i] = fPlugin.getParameterValue(i); | |||
} | |||
} | |||
else | |||
{ | |||
fPortControls = nullptr; | |||
fLastControlValues = nullptr; | |||
} | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
fPortEventsIn = nullptr; | |||
@@ -224,6 +231,9 @@ public: | |||
#if DISTRHO_LV2_USE_EVENTS_IN | |||
# if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t midiEventCount = 0; | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
bool needsFrameIncrement = true; | |||
# endif | |||
LV2_ATOM_SEQUENCE_FOREACH(fPortEventsIn, event) | |||
{ | |||
@@ -254,9 +264,118 @@ public: | |||
} | |||
# endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
if (event->body.type == fURIDs.timePosition) | |||
if (event->body.type == fURIDs.atomBlank) | |||
{ | |||
// TODO | |||
const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body); | |||
if (obj->body.otype != fURIDs.timePosition) | |||
continue; | |||
LV2_Atom* bar = nullptr; | |||
LV2_Atom* barBeat = nullptr; | |||
LV2_Atom* beat = nullptr; | |||
LV2_Atom* beatUnit = nullptr; | |||
LV2_Atom* beatsPerBar = nullptr; | |||
LV2_Atom* beatsPerMinute = nullptr; | |||
LV2_Atom* frame = nullptr; | |||
LV2_Atom* speed = nullptr; | |||
lv2_atom_object_get(obj, | |||
fURIDs.timeBar, &bar, | |||
fURIDs.timeBarBeat, &barBeat, | |||
fURIDs.timeBeat, &beat, | |||
fURIDs.timeBeatUnit, &beatUnit, | |||
fURIDs.timeBeatsPerBar, &beatsPerBar, | |||
fURIDs.timeBeatsPerMinute, &beatsPerMinute, | |||
fURIDs.timeFrame, &frame, | |||
fURIDs.timeSpeed, &speed, | |||
nullptr); | |||
// TODO: | |||
// - tick | |||
// - barStartTick | |||
// - ticksPerBeat | |||
if (bar != nullptr) | |||
{ | |||
if (bar->type == fURIDs.atomDouble) | |||
fTimePos.bbt.bar = ((LV2_Atom_Double*)bar)->body + 1.0f; | |||
else if (bar->type == fURIDs.atomFloat) | |||
fTimePos.bbt.bar = ((LV2_Atom_Float*)bar)->body + 1.0f; | |||
else if (bar->type == fURIDs.atomInt) | |||
fTimePos.bbt.bar = ((LV2_Atom_Int*)bar)->body + 1; | |||
else if (bar->type == fURIDs.atomLong) | |||
fTimePos.bbt.bar = ((LV2_Atom_Long*)bar)->body + 1; | |||
} | |||
/*if (barBeat != nullptr && barBeat->type == fURIDs.atomFloat) | |||
{ | |||
}*/ | |||
if (beat != nullptr) | |||
{ | |||
if (beat->type == fURIDs.atomDouble) | |||
fTimePos.bbt.beat = ((LV2_Atom_Double*)beat)->body + 1.0f; | |||
else if (beat->type == fURIDs.atomFloat) | |||
fTimePos.bbt.beat = ((LV2_Atom_Float*)beat)->body + 1.0f; | |||
else if (beat->type == fURIDs.atomInt) | |||
fTimePos.bbt.beat = ((LV2_Atom_Int*)beat)->body + 1; | |||
else if (beat->type == fURIDs.atomLong) | |||
fTimePos.bbt.beat = ((LV2_Atom_Long*)beat)->body + 1; | |||
} | |||
if (beatUnit != nullptr) | |||
{ | |||
if (beatUnit->type == fURIDs.atomDouble) | |||
fTimePos.bbt.beatType = ((LV2_Atom_Double*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomFloat) | |||
fTimePos.bbt.beatType = ((LV2_Atom_Float*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomInt) | |||
fTimePos.bbt.beatType = ((LV2_Atom_Int*)beatUnit)->body; | |||
else if (beatUnit->type == fURIDs.atomLong) | |||
fTimePos.bbt.beatType = ((LV2_Atom_Long*)beatUnit)->body; | |||
} | |||
if (beatsPerBar != nullptr) | |||
{ | |||
if (beatsPerBar->type == fURIDs.atomDouble) | |||
fTimePos.bbt.beatsPerBar = ((LV2_Atom_Double*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomFloat) | |||
fTimePos.bbt.beatsPerBar = ((LV2_Atom_Float*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomInt) | |||
fTimePos.bbt.beatsPerBar = ((LV2_Atom_Int*)beatsPerBar)->body; | |||
else if (beatsPerBar->type == fURIDs.atomLong) | |||
fTimePos.bbt.beatsPerBar = ((LV2_Atom_Long*)beatsPerBar)->body; | |||
} | |||
if (beatsPerMinute != nullptr) | |||
{ | |||
if (beatsPerMinute->type == fURIDs.atomDouble) | |||
fTimePos.bbt.beatsPerMinute = ((LV2_Atom_Double*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomFloat) | |||
fTimePos.bbt.beatsPerMinute = ((LV2_Atom_Float*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomInt) | |||
fTimePos.bbt.beatsPerMinute = ((LV2_Atom_Int*)beatsPerMinute)->body; | |||
else if (beatsPerMinute->type == fURIDs.atomLong) | |||
fTimePos.bbt.beatsPerMinute = ((LV2_Atom_Long*)beatsPerMinute)->body; | |||
} | |||
if (frame != nullptr && frame->type == fURIDs.atomLong) | |||
{ | |||
fTimePos.frame = ((LV2_Atom_Long*)frame)->body; | |||
needsFrameIncrement = false; | |||
} | |||
if (speed != nullptr && speed->type == fURIDs.atomFloat) | |||
{ | |||
fLastTimeSpeed = ((LV2_Atom_Float*)speed)->body; | |||
fTimePos.playing = (fLastTimeSpeed == 1.0f); | |||
} | |||
if ((! fTimePos.bbt.valid) && beatsPerMinute != nullptr && beatsPerBar != nullptr && beatUnit != nullptr) | |||
fTimePos.bbt.valid = true; | |||
continue; | |||
} | |||
# endif | |||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | |||
@@ -264,11 +383,19 @@ public: | |||
{ | |||
const void* const data((const void*)(event + 1)); | |||
fWorker->schedule_work(fWorker->handle, event->body.size, data); | |||
continue; | |||
} | |||
# endif | |||
} | |||
#endif | |||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
if (needsFrameIncrement && fLastTimeSpeed != 0.0f) | |||
fTimePos.frame += fLastTimeSpeed*sampleCount; | |||
fPlugin.setTimePos(fTimePos); | |||
# endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
fPlugin.run(fPortAudioIns, fPortAudioOuts, sampleCount, fMidiEvents, midiEventCount); | |||
#else | |||
@@ -459,20 +586,50 @@ private: | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
TimePos fTimePos; | |||
float fLastTimeSpeed; | |||
#endif | |||
// LV2 URIDs | |||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | |||
struct URIDs { | |||
LV2_URID atomBlank; | |||
LV2_URID atomDouble; | |||
LV2_URID atomFloat; | |||
LV2_URID atomInt; | |||
LV2_URID atomLong; | |||
LV2_URID atomString; | |||
LV2_URID distrhoState; | |||
LV2_URID midiEvent; | |||
LV2_URID timePosition; | |||
LV2_URID timeBar; | |||
LV2_URID timeBarBeat; | |||
LV2_URID timeBeat; | |||
LV2_URID timeBeatUnit; | |||
LV2_URID timeBeatsPerBar; | |||
LV2_URID timeBeatsPerMinute; | |||
LV2_URID timeFrame; | |||
LV2_URID timeSpeed; | |||
URIDs(const LV2_URID_Map* const uridMap) | |||
: atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | |||
: atomBlank(uridMap->map(uridMap->handle, LV2_ATOM__Blank)), | |||
atomDouble(uridMap->map(uridMap->handle, LV2_ATOM__Double)), | |||
atomFloat(uridMap->map(uridMap->handle, LV2_ATOM__Float)), | |||
atomInt(uridMap->map(uridMap->handle, LV2_ATOM__Int)), | |||
atomLong(uridMap->map(uridMap->handle, LV2_ATOM__Long)), | |||
atomString(uridMap->map(uridMap->handle, LV2_ATOM__String)), | |||
distrhoState(uridMap->map(uridMap->handle, "urn:distrho:keyValueState")), | |||
midiEvent(uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent)), | |||
timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)) {} | |||
timePosition(uridMap->map(uridMap->handle, LV2_TIME__Position)), | |||
timeBar(uridMap->map(uridMap->handle, LV2_TIME__bar)), | |||
timeBarBeat(uridMap->map(uridMap->handle, LV2_TIME__barBeat)), | |||
timeBeat(uridMap->map(uridMap->handle, LV2_TIME__beat)), | |||
timeBeatUnit(uridMap->map(uridMap->handle, LV2_TIME__beatUnit)), | |||
timeBeatsPerBar(uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar)), | |||
timeBeatsPerMinute(uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute)), | |||
timeFrame(uridMap->map(uridMap->handle, LV2_TIME__frame)), | |||
timeSpeed(uridMap->map(uridMap->handle, LV2_TIME__speed)) {} | |||
} fURIDs; | |||
#endif | |||
@@ -563,6 +720,8 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||
} | |||
#endif | |||
d_lastBufferSize = 0; | |||
for (int i=0; options[i].key != 0; ++i) | |||
{ | |||
if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) | |||
@@ -577,7 +736,10 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||
} | |||
if (d_lastBufferSize == 0) | |||
{ | |||
d_stderr("Host does not provide maxBlockLength option"); | |||
d_lastBufferSize = 2048; | |||
} | |||
d_lastSampleRate = sampleRate; | |||
@@ -45,6 +45,7 @@ | |||
#define effCanBeAutomated 26 | |||
#define effGetProgramNameIndexed 29 | |||
#define effGetPlugCategory 35 | |||
#define effIdle 53 | |||
#define kPlugCategEffect 1 | |||
#define kPlugCategSynth 2 | |||
#define kVstVersion 2400 | |||
@@ -55,6 +56,13 @@ struct ERect { | |||
# include "vst/aeffectx.h" | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
# warning VST State still TODO (working but needs final testing) | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
# warning VST TimePos still TODO | |||
#endif | |||
typedef std::map<d_string,d_string> StringMap; | |||
START_NAMESPACE_DISTRHO | |||
@@ -437,6 +445,11 @@ public: | |||
case effEditOpen: | |||
if (fVstUi == nullptr) | |||
{ | |||
# if DISTRHO_OS_MAC && ! defined(__LP64__) | |||
if ((fEffect->dispatcher(fEffect, effCanDo, 0, 0, (void*)"hasCockosViewAsConfig", 0.0f) & 0xffff0000) != 0xbeef0000) | |||
return 0; | |||
# endif | |||
d_lastUiSampleRate = fAudioMaster(fEffect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||
fVstUi = new UIVst(fAudioMaster, fEffect, &fPlugin, this, (intptr_t)ptr); | |||
@@ -478,6 +491,7 @@ public: | |||
break; | |||
case effEditIdle: | |||
case effIdle: | |||
if (fVstUi != nullptr) | |||
fVstUi->idle(); | |||
break; | |||
@@ -657,7 +671,15 @@ public: | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
if (const VstTimeInfo* const timeInfo = (const VstTimeInfo*)fEffect->dispatcher(fEffect, audioMasterGetTime, 0, kVstTempoValid, nullptr, 0.0f)) | |||
fPlugin.setTimePos((timeInfo->flags & kVstTransportPlaying) != 0, timeInfo->samplePos, timeInfo->tempo); | |||
{ | |||
fTimePos.playing = (timeInfo->flags & kVstTransportPlaying); | |||
fTimePos.frame = timeInfo->samplePos; | |||
// TODO: BBT | |||
// timeInfo->tempo etc | |||
fPlugin.setTimePos(fTimePos); | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
@@ -681,14 +703,20 @@ private: | |||
PluginExporter fPlugin; | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
// Current state | |||
int32_t fCurProgram; | |||
#endif | |||
// Temporary data | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t fMidiEventCount; | |||
MidiEvent fMidiEvents[kMaxMidiEvents]; | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_TIMEPOS | |||
TimePos fTimePos; | |||
#endif | |||
// UI stuff | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
UIVst* fVstUi; | |||
ERect fVstRect; | |||
@@ -16,9 +16,6 @@ | |||
#include "DistrhoUIInternal.hpp" | |||
#include "dgl/App.hpp" | |||
#include "dgl/Window.hpp" | |||
#include <lo/lo.h> | |||
START_NAMESPACE_DISTRHO | |||
@@ -19,8 +19,8 @@ | |||
#include "../DistrhoUI.hpp" | |||
#include "../dgl/App.hpp" | |||
#include "../dgl/Window.hpp" | |||
#include "../../dgl/App.hpp" | |||
#include "../../dgl/Window.hpp" | |||
START_NAMESPACE_DISTRHO | |||
@@ -1,365 +0,0 @@ | |||
/* | |||
* DISTRHO Plugin Toolkit (DPT) | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | |||
* or without fee is hereby granted, provided that the above copyright notice and this | |||
* permission notice appear in all copies. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifdef DISTRHO_PLUGIN_TARGET_JACK | |||
#include "DistrhoDefines.h" | |||
#if ! DISTRHO_PLUGIN_HAS_UI | |||
# error Standalone JACK mode requires UI | |||
#endif | |||
#include "DistrhoPluginInternal.h" | |||
#include "DistrhoUIInternal.h" | |||
#include <jack/jack.h> | |||
#include <jack/midiport.h> | |||
#include <jack/transport.h> | |||
#include <QtCore/QSettings> | |||
#include <QtGui/QApplication> | |||
#include <QtGui/QMainWindow> | |||
#include <QtGui/QMessageBox> | |||
// ------------------------------------------------- | |||
START_NAMESPACE_DISTRHO | |||
class PluginJack : public QMainWindow | |||
{ | |||
public: | |||
PluginJack(jack_client_t* client_) | |||
: QMainWindow(nullptr), | |||
widget(this), | |||
settings("DISTRHO", DISTRHO_PLUGIN_NAME), | |||
ui(this, widget.winId(), setParameterCallback, setStateCallback, nullptr, uiNoteCallback, uiResizeCallback), | |||
client(client_) | |||
{ | |||
setCentralWidget(&widget); | |||
setFixedSize(ui.getWidth(), ui.getHeight()); | |||
setWindowTitle(DISTRHO_PLUGIN_NAME); | |||
if (DISTRHO_PLUGIN_NUM_INPUTS > 0) | |||
{ | |||
portsIn = new jack_port_t* [DISTRHO_PLUGIN_NUM_INPUTS]; | |||
for (int i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++) | |||
portsIn[i] = jack_port_register(client, d_string("Audio Input ") + d_string(i+1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
} | |||
else | |||
portsIn = nullptr; | |||
if (DISTRHO_PLUGIN_NUM_OUTPUTS > 0) | |||
{ | |||
portsOut = new jack_port_t* [DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
for (int i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++) | |||
portsOut[i] = jack_port_register(client, d_string("Audio Output ") + d_string(i+1), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
} | |||
else | |||
portsOut = nullptr; | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
portMidi = jack_port_register(client, "Midi Input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
#endif | |||
jack_set_process_callback(client, jackProcessCallback, this); | |||
uiTimer = startTimer(30); | |||
// load settings | |||
restoreGeometry(settings.value("Global/Geometry", QByteArray()).toByteArray()); | |||
for (uint32_t i=0; i < plugin.parameterCount(); i++) | |||
{ | |||
bool ok; | |||
float value = settings.value(QString("Parameters/%1").arg(i)).toFloat(&ok); | |||
if (ok) | |||
{ | |||
plugin.setParameterValue(i, value); | |||
ui.parameterChanged(i, value); | |||
} | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
for (uint32_t i=0; i < plugin.stateCount(); i++) | |||
{ | |||
const char* key = plugin.stateKey(i); | |||
QString stringValue(settings.value(key).toString()); | |||
if (! stringValue.isEmpty()) | |||
ui.stateChanged(key, stringValue.toUtf8().constData()); | |||
} | |||
#endif | |||
} | |||
~PluginJack() | |||
{ | |||
// save settings | |||
settings.setValue("Global/Geometry", saveGeometry()); | |||
if (uiTimer) | |||
killTimer(uiTimer); | |||
if (portsIn) | |||
delete[] portsIn; | |||
if (portsOut) | |||
delete[] portsOut; | |||
} | |||
// --------------------------------------------- | |||
protected: | |||
void setParameterValue(uint32_t index, float value) | |||
{ | |||
plugin.setParameterValue(index, value); | |||
settings.setValue(QString("Parameters/%1").arg(index), value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
void setState(const char* key, const char* value) | |||
{ | |||
plugin.setState(key, value); | |||
settings.setValue(key, value); | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
void uiNote(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
// TODO | |||
} | |||
#endif | |||
void uiResize(unsigned int width, unsigned int height) | |||
{ | |||
widget.setFixedSize(width, height); | |||
setFixedSize(width, height); | |||
} | |||
int jackProcess(jack_nframes_t nframes) | |||
{ | |||
if (nframes <= 1) | |||
return 1; | |||
// Check for updated bufferSize | |||
if (nframes != d_lastBufferSize) | |||
{ | |||
d_lastBufferSize = nframes; | |||
plugin.setBufferSize(nframes, true); | |||
} | |||
const float* ins[DISTRHO_PLUGIN_NUM_INPUTS]; | |||
float* outs[DISTRHO_PLUGIN_NUM_OUTPUTS]; | |||
for (int i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; i++) | |||
ins[i] = (float*)jack_port_get_buffer(portsIn[i], nframes); | |||
for (int i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; i++) | |||
outs[i] = (float*)jack_port_get_buffer(portsOut[i], nframes); | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
uint32_t midiEventCount = 0; | |||
void* mIn = jack_port_get_buffer(portMidi, nframes); | |||
// TODO | |||
plugin.run(ins, outs, nframes, midiEventCount, midiEvents); | |||
#else | |||
plugin.run(ins, outs, nframes, 0, nullptr); | |||
#endif | |||
return 0; | |||
} | |||
// --------------------------------------------- | |||
void closeEvent(QCloseEvent* event) | |||
{ | |||
QMainWindow::closeEvent(event); | |||
qApp->quit(); | |||
} | |||
void timerEvent(QTimerEvent* event) | |||
{ | |||
if (event->timerId() == uiTimer) | |||
ui.idle(); | |||
QMainWindow::timerEvent(event); | |||
} | |||
// --------------------------------------------- | |||
private: | |||
// Qt4 stuff | |||
int uiTimer; | |||
QWidget widget; | |||
QSettings settings; | |||
PluginInternal plugin; | |||
UIInternal ui; | |||
jack_client_t* const client; | |||
jack_port_t** portsIn; | |||
jack_port_t** portsOut; | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
jack_port_t* portMidi; | |||
MidiEvent midiEvents[MAX_MIDI_EVENTS]; | |||
#endif | |||
// --------------------------------------------- | |||
// Callbacks | |||
static void setParameterCallback(void* ptr, uint32_t index, float value) | |||
{ | |||
PluginJack* _this_ = (PluginJack*)ptr; | |||
assert(_this_); | |||
_this_->setParameterValue(index, value); | |||
} | |||
static void setStateCallback(void* ptr, const char* key, const char* value) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
PluginJack* _this_ = (PluginJack*)ptr; | |||
assert(_this_); | |||
_this_->setState(key, value); | |||
#else | |||
Q_UNUSED(ptr); | |||
Q_UNUSED(key); | |||
Q_UNUSED(value); | |||
#endif | |||
} | |||
static void uiNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
PluginJack* _this_ = (PluginJack*)ptr; | |||
assert(_this_); | |||
_this_->uiNote(onOff, channel, note, velocity); | |||
#else | |||
Q_UNUSED(ptr); | |||
Q_UNUSED(onOff); | |||
Q_UNUSED(channel); | |||
Q_UNUSED(note); | |||
Q_UNUSED(velocity); | |||
#endif | |||
} | |||
static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
{ | |||
PluginJack* _this_ = (PluginJack*)ptr; | |||
assert(_this_); | |||
_this_->uiResize(width, height); | |||
} | |||
static int jackProcessCallback(jack_nframes_t nframes, void* arg) | |||
{ | |||
PluginJack* _this_ = (PluginJack*)arg; | |||
assert(_this_); | |||
return _this_->jackProcess(nframes); | |||
} | |||
}; | |||
// ------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
// ------------------------------------------------- | |||
std::string jack_status_get_error_string(const jack_status_t& status) | |||
{ | |||
std::string errorString; | |||
if (status & JackFailure) | |||
errorString += "Overall operation failed;\n"; | |||
if (status & JackInvalidOption) | |||
errorString += "The operation contained an invalid or unsupported option;\n"; | |||
if (status & JackNameNotUnique) | |||
errorString += "The desired client name was not unique;\n"; | |||
if (status & JackServerStarted) | |||
errorString += "The JACK server was started as a result of this operation;\n"; | |||
if (status & JackServerFailed) | |||
errorString += "Unable to connect to the JACK server;\n"; | |||
if (status & JackServerError) | |||
errorString += "Communication error with the JACK server;\n"; | |||
if (status & JackNoSuchClient) | |||
errorString += "Requested client does not exist;\n"; | |||
if (status & JackLoadFailure) | |||
errorString += "Unable to load internal client;\n"; | |||
if (status & JackInitFailure) | |||
errorString += "Unable to initialize client;\n"; | |||
if (status & JackShmFailure) | |||
errorString += "Unable to access shared memory;\n"; | |||
if (status & JackVersionError) | |||
errorString += "Client's protocol version does not match;\n"; | |||
if (status & JackBackendError) | |||
errorString += "Backend Error;\n"; | |||
if (status & JackClientZombie) | |||
errorString += "Client is being shutdown against its will;\n"; | |||
if (errorString.size() > 0) | |||
errorString.replace(errorString.size()-2, 2, "."); | |||
return errorString; | |||
} | |||
int main(int argc, char* argv[]) | |||
{ | |||
USE_NAMESPACE_DISTRHO | |||
QApplication app(argc, argv, true); | |||
jack_status_t status; | |||
jack_client_t* client = jack_client_open(DISTRHO_PLUGIN_NAME, JackNullOption, &status); | |||
if (! client) | |||
{ | |||
std::string errorString(jack_status_get_error_string(status)); | |||
QMessageBox::critical(nullptr, app.translate(DISTRHO_PLUGIN_NAME, "Error"), | |||
app.translate(DISTRHO_PLUGIN_NAME, | |||
"Could not connect to JACK, possible reasons:\n" | |||
"%1").arg(QString::fromStdString(errorString))); | |||
return 1; | |||
} | |||
d_lastBufferSize = jack_get_buffer_size(client); | |||
d_lastSampleRate = jack_get_sample_rate(client); | |||
setLastUiSampleRate(d_lastSampleRate); | |||
PluginJack plugin(client); | |||
plugin.show(); | |||
jack_activate(client); | |||
int ret = app.exec(); | |||
jack_deactivate(client); | |||
jack_client_close(client); | |||
return ret; | |||
} | |||
// ------------------------------------------------- | |||
#endif // DISTRHO_PLUGIN_TARGET_JACK |
@@ -0,0 +1,441 @@ | |||
/* -*- c-basic-offset: 4 -*- */ | |||
/* dssi.h | |||
DSSI version 1.0 | |||
Copyright (c) 2004, 2009 Chris Cannam, Steve Harris and Sean Bolton | |||
This library is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public License | |||
as published by the Free Software Foundation; either version 2.1 of | |||
the License, or (at your option) any later version. | |||
This library 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 | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |||
MA 02110-1301 USA | |||
*/ | |||
#ifndef DSSI_INCLUDED | |||
#define DSSI_INCLUDED | |||
#include "../ladspa/ladspa.h" | |||
#include "seq_event-compat.h" | |||
#define DSSI_VERSION "1.0" | |||
#define DSSI_VERSION_MAJOR 1 | |||
#define DSSI_VERSION_MINOR 0 | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/* | |||
There is a need for an API that supports hosted MIDI soft synths | |||
with GUIs in Linux audio applications. In time the GMPI initiative | |||
should comprehensively address this need, but the requirement for | |||
Linux applications to be able to support simple hosted synths is | |||
here now, and GMPI is not. This proposal (the "DSSI Soft Synth | |||
Interface" or DSSI, pronounced "dizzy") aims to provide a simple | |||
solution in a way that we hope will prove complete and compelling | |||
enough to support now, yet not so compelling as to supplant GMPI or | |||
any other comprehensive future proposal. | |||
For simplicity and familiarity, this API is based as far as | |||
possible on existing work -- the LADSPA plugin API for control | |||
values and audio processing, and the ALSA sequencer event types for | |||
MIDI event communication. The GUI part of the proposal is quite | |||
new, but may also be applicable retroactively to LADSPA plugins | |||
that do not otherwise support this synth interface. | |||
*/ | |||
typedef struct _DSSI_Program_Descriptor { | |||
/** Bank number for this program. Note that DSSI does not support | |||
MIDI-style separation of bank LSB and MSB values. There is no | |||
restriction on the set of available banks: the numbers do not | |||
need to be contiguous, there does not need to be a bank 0, etc. */ | |||
unsigned long Bank; | |||
/** Program number (unique within its bank) for this program. | |||
There is no restriction on the set of available programs: the | |||
numbers do not need to be contiguous, there does not need to | |||
be a program 0, etc. */ | |||
unsigned long Program; | |||
/** Name of the program. */ | |||
const char * Name; | |||
} DSSI_Program_Descriptor; | |||
typedef struct _DSSI_Descriptor { | |||
/** | |||
* DSSI_API_Version | |||
* | |||
* This member indicates the DSSI API level used by this plugin. | |||
* If we're lucky, this will never be needed. For now all plugins | |||
* must set it to 1. | |||
*/ | |||
int DSSI_API_Version; | |||
/** | |||
* LADSPA_Plugin | |||
* | |||
* A DSSI synth plugin consists of a LADSPA plugin plus an | |||
* additional framework for controlling program settings and | |||
* transmitting MIDI events. A plugin must fully implement the | |||
* LADSPA descriptor fields as well as the required LADSPA | |||
* functions including instantiate() and (de)activate(). It | |||
* should also implement run(), with the same behaviour as if | |||
* run_synth() (below) were called with no synth events. | |||
* | |||
* In order to instantiate a synth the host calls the LADSPA | |||
* instantiate function, passing in this LADSPA_Descriptor | |||
* pointer. The returned LADSPA_Handle is used as the argument | |||
* for the DSSI functions below as well as for the LADSPA ones. | |||
*/ | |||
const LADSPA_Descriptor *LADSPA_Plugin; | |||
/** | |||
* configure() | |||
* | |||
* This member is a function pointer that sends a piece of | |||
* configuration data to the plugin. The key argument specifies | |||
* some aspect of the synth's configuration that is to be changed, | |||
* and the value argument specifies a new value for it. A plugin | |||
* that does not require this facility at all may set this member | |||
* to NULL. | |||
* | |||
* This call is intended to set some session-scoped aspect of a | |||
* plugin's behaviour, for example to tell the plugin to load | |||
* sample data from a particular file. The plugin should act | |||
* immediately on the request. The call should return NULL on | |||
* success, or an error string that may be shown to the user. The | |||
* host will free the returned value after use if it is non-NULL. | |||
* | |||
* Calls to configure() are not automated as timed events. | |||
* Instead, a host should remember the last value associated with | |||
* each key passed to configure() during a given session for a | |||
* given plugin instance, and should call configure() with the | |||
* correct value for each key the next time it instantiates the | |||
* "same" plugin instance, for example on reloading a project in | |||
* which the plugin was used before. Plugins should note that a | |||
* host may typically instantiate a plugin multiple times with the | |||
* same configuration values, and should share data between | |||
* instances where practical. | |||
* | |||
* Calling configure() completely invalidates the program and bank | |||
* information last obtained from the plugin. | |||
* | |||
* Reserved and special key prefixes | |||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |||
* The DSSI: prefix | |||
* ---------------- | |||
* Configure keys starting with DSSI: are reserved for particular | |||
* purposes documented in the DSSI specification. At the moment, | |||
* there is one such key: DSSI:PROJECT_DIRECTORY. A host may call | |||
* configure() passing this key and a directory path value. This | |||
* indicates to the plugin and its UI that a directory at that | |||
* path exists and may be used for project-local data. Plugins | |||
* may wish to use the project directory as a fallback location | |||
* when looking for other file data, or as a base for relative | |||
* paths in other configuration values. | |||
* | |||
* The GLOBAL: prefix | |||
* ------------------ | |||
* Configure keys starting with GLOBAL: may be used by the plugin | |||
* and its UI for any purpose, but are treated specially by the | |||
* host. When one of these keys is used in a configure OSC call | |||
* from the plugin UI, the host makes the corresponding configure | |||
* call (preserving the GLOBAL: prefix) not only to the target | |||
* plugin but also to all other plugins in the same instance | |||
* group, as well as their UIs. Note that if any instance | |||
* returns non-NULL from configure to indicate error, the host | |||
* may stop there (and the set of plugins on which configure has | |||
* been called will thus depend on the host implementation). | |||
* See also the configure OSC call documentation in RFC.txt. | |||
*/ | |||
char *(*configure)(LADSPA_Handle Instance, | |||
const char *Key, | |||
const char *Value); | |||
#define DSSI_RESERVED_CONFIGURE_PREFIX "DSSI:" | |||
#define DSSI_GLOBAL_CONFIGURE_PREFIX "GLOBAL:" | |||
#define DSSI_PROJECT_DIRECTORY_KEY \ | |||
DSSI_RESERVED_CONFIGURE_PREFIX "PROJECT_DIRECTORY" | |||
/** | |||
* get_program() | |||
* | |||
* This member is a function pointer that provides a description | |||
* of a program (named preset sound) available on this synth. A | |||
* plugin that does not support programs at all should set this | |||
* member to NULL. | |||
* | |||
* The Index argument is an index into the plugin's list of | |||
* programs, not a program number as represented by the Program | |||
* field of the DSSI_Program_Descriptor. (This distinction is | |||
* needed to support synths that use non-contiguous program or | |||
* bank numbers.) | |||
* | |||
* This function returns a DSSI_Program_Descriptor pointer that is | |||
* guaranteed to be valid only until the next call to get_program, | |||
* deactivate, or configure, on the same plugin instance. This | |||
* function must return NULL if passed an Index argument out of | |||
* range, so that the host can use it to query the number of | |||
* programs as well as their properties. | |||
*/ | |||
const DSSI_Program_Descriptor *(*get_program)(LADSPA_Handle Instance, | |||
unsigned long Index); | |||
/** | |||
* select_program() | |||
* | |||
* This member is a function pointer that selects a new program | |||
* for this synth. The program change should take effect | |||
* immediately at the start of the next run_synth() call. (This | |||
* means that a host providing the capability of changing programs | |||
* between any two notes on a track must vary the block size so as | |||
* to place the program change at the right place. A host that | |||
* wanted to avoid this would probably just instantiate a plugin | |||
* for each program.) | |||
* | |||
* A plugin that does not support programs at all should set this | |||
* member NULL. Plugins should ignore a select_program() call | |||
* with an invalid bank or program. | |||
* | |||
* A plugin is not required to select any particular default | |||
* program on activate(): it's the host's duty to set a program | |||
* explicitly. The current program is invalidated by any call to | |||
* configure(). | |||
* | |||
* A plugin is permitted to re-write the values of its input | |||
* control ports when select_program is called. The host should | |||
* re-read the input control port values and update its own | |||
* records appropriately. (This is the only circumstance in | |||
* which a DSSI plugin is allowed to modify its own input ports.) | |||
*/ | |||
void (*select_program)(LADSPA_Handle Instance, | |||
unsigned long Bank, | |||
unsigned long Program); | |||
/** | |||
* get_midi_controller_for_port() | |||
* | |||
* This member is a function pointer that returns the MIDI | |||
* controller number or NRPN that should be mapped to the given | |||
* input control port. If the given port should not have any MIDI | |||
* controller mapped to it, the function should return DSSI_NONE. | |||
* The behaviour of this function is undefined if the given port | |||
* number does not correspond to an input control port. A plugin | |||
* that does not want MIDI controllers mapped to ports at all may | |||
* set this member NULL. | |||
* | |||
* Correct values can be got using the macros DSSI_CC(num) and | |||
* DSSI_NRPN(num) as appropriate, and values can be combined using | |||
* bitwise OR: e.g. DSSI_CC(23) | DSSI_NRPN(1069) means the port | |||
* should respond to CC #23 and NRPN #1069. | |||
* | |||
* The host is responsible for doing proper scaling from MIDI | |||
* controller and NRPN value ranges to port ranges according to | |||
* the plugin's LADSPA port hints. Hosts should not deliver | |||
* through run_synth any MIDI controller events that have already | |||
* been mapped to control port values. | |||
* | |||
* A plugin should not attempt to request mappings from | |||
* controllers 0 or 32 (MIDI Bank Select MSB and LSB). | |||
*/ | |||
int (*get_midi_controller_for_port)(LADSPA_Handle Instance, | |||
unsigned long Port); | |||
/** | |||
* run_synth() | |||
* | |||
* This member is a function pointer that runs a synth for a | |||
* block. This is identical in function to the LADSPA run() | |||
* function, except that it also supplies events to the synth. | |||
* | |||
* A plugin may provide this function, run_multiple_synths() (see | |||
* below), both, or neither (if it is not in fact a synth). A | |||
* plugin that does not provide this function must set this member | |||
* to NULL. Authors of synth plugins are encouraged to provide | |||
* this function if at all possible. | |||
* | |||
* The Events pointer points to a block of EventCount ALSA | |||
* sequencer events, which is used to communicate MIDI and related | |||
* events to the synth. Each event is timestamped relative to the | |||
* start of the block, (mis)using the ALSA "tick time" field as a | |||
* frame count. The host is responsible for ensuring that events | |||
* with differing timestamps are already ordered by time. | |||
* | |||
* See also the notes on activation, port connection etc in | |||
* ladpsa.h, in the context of the LADSPA run() function. | |||
* | |||
* Note Events | |||
* ~~~~~~~~~~~ | |||
* There are two minor requirements aimed at making the plugin | |||
* writer's life as simple as possible: | |||
* | |||
* 1. A host must never send events of type SND_SEQ_EVENT_NOTE. | |||
* Notes should always be sent as separate SND_SEQ_EVENT_NOTE_ON | |||
* and NOTE_OFF events. A plugin should discard any one-point | |||
* NOTE events it sees. | |||
* | |||
* 2. A host must not attempt to switch notes off by sending | |||
* zero-velocity NOTE_ON events. It should always send true | |||
* NOTE_OFFs. It is the host's responsibility to remap events in | |||
* cases where an external MIDI source has sent it zero-velocity | |||
* NOTE_ONs. | |||
* | |||
* Bank and Program Events | |||
* ~~~~~~~~~~~~~~~~~~~~~~~ | |||
* Hosts must map MIDI Bank Select MSB and LSB (0 and 32) | |||
* controllers and MIDI Program Change events onto the banks and | |||
* programs specified by the plugin, using the DSSI select_program | |||
* call. No host should ever deliver a program change or bank | |||
* select controller to a plugin via run_synth. | |||
*/ | |||
void (*run_synth)(LADSPA_Handle Instance, | |||
unsigned long SampleCount, | |||
snd_seq_event_t *Events, | |||
unsigned long EventCount); | |||
/** | |||
* run_synth_adding() | |||
* | |||
* This member is a function pointer that runs an instance of a | |||
* synth for a block, adding its outputs to the values already | |||
* present at the output ports. This is provided for symmetry | |||
* with LADSPA run_adding(), and is equally optional. A plugin | |||
* that does not provide it must set this member to NULL. | |||
*/ | |||
void (*run_synth_adding)(LADSPA_Handle Instance, | |||
unsigned long SampleCount, | |||
snd_seq_event_t *Events, | |||
unsigned long EventCount); | |||
/** | |||
* run_multiple_synths() | |||
* | |||
* This member is a function pointer that runs multiple synth | |||
* instances for a block. This is very similar to run_synth(), | |||
* except that Instances, Events, and EventCounts each point to | |||
* arrays that hold the LADSPA handles, event buffers, and | |||
* event counts for each of InstanceCount instances. That is, | |||
* Instances points to an array of InstanceCount pointers to | |||
* DSSI plugin instantiations, Events points to an array of | |||
* pointers to each instantiation's respective event list, and | |||
* EventCounts points to an array containing each instantiation's | |||
* respective event count. | |||
* | |||
* A host using this function must guarantee that ALL active | |||
* instances of the plugin are represented in each call to the | |||
* function -- that is, a host may not call run_multiple_synths() | |||
* for some instances of a given plugin and then call run_synth() | |||
* as well for others. 'All .. instances of the plugin' means | |||
* every instance sharing the same LADSPA label and shared object | |||
* (*.so) file (rather than every instance sharing the same *.so). | |||
* 'Active' means any instance for which activate() has been called | |||
* but deactivate() has not. | |||
* | |||
* A plugin may provide this function, run_synths() (see above), | |||
* both, or neither (if it not in fact a synth). A plugin that | |||
* does not provide this function must set this member to NULL. | |||
* Plugin authors implementing run_multiple_synths are strongly | |||
* encouraged to implement run_synth as well if at all possible, | |||
* to aid simplistic hosts, even where it would be less efficient | |||
* to use it. | |||
*/ | |||
void (*run_multiple_synths)(unsigned long InstanceCount, | |||
LADSPA_Handle *Instances, | |||
unsigned long SampleCount, | |||
snd_seq_event_t **Events, | |||
unsigned long *EventCounts); | |||
/** | |||
* run_multiple_synths_adding() | |||
* | |||
* This member is a function pointer that runs multiple synth | |||
* instances for a block, adding each synth's outputs to the | |||
* values already present at the output ports. This is provided | |||
* for symmetry with both the DSSI run_multiple_synths() and LADSPA | |||
* run_adding() functions, and is equally optional. A plugin | |||
* that does not provide it must set this member to NULL. | |||
*/ | |||
void (*run_multiple_synths_adding)(unsigned long InstanceCount, | |||
LADSPA_Handle *Instances, | |||
unsigned long SampleCount, | |||
snd_seq_event_t **Events, | |||
unsigned long *EventCounts); | |||
/** | |||
* set_custom_data() | |||
*/ | |||
int (*set_custom_data)(LADSPA_Handle Instance, | |||
void *Data, | |||
unsigned long DataLength); | |||
/** | |||
* get_custom_data() | |||
*/ | |||
int (*get_custom_data)(LADSPA_Handle Instance, | |||
void **Data, | |||
unsigned long *DataLength); | |||
} DSSI_Descriptor; | |||
/** | |||
* DSSI supports a plugin discovery method similar to that of LADSPA: | |||
* | |||
* - DSSI hosts may wish to locate DSSI plugin shared object files by | |||
* searching the paths contained in the DSSI_PATH and LADSPA_PATH | |||
* environment variables, if they are present. Both are expected | |||
* to be colon-separated lists of directories to be searched (in | |||
* order), and DSSI_PATH should be searched first if both variables | |||
* are set. | |||
* | |||
* - Each shared object file containing DSSI plugins must include a | |||
* function dssi_descriptor(), with the following function prototype | |||
* and C-style linkage. Hosts may enumerate the plugin types | |||
* available in the shared object file by repeatedly calling | |||
* this function with successive Index values (beginning from 0), | |||
* until a return value of NULL indicates no more plugin types are | |||
* available. Each non-NULL return is the DSSI_Descriptor | |||
* of a distinct plugin type. | |||
*/ | |||
const DSSI_Descriptor *dssi_descriptor(unsigned long Index); | |||
typedef const DSSI_Descriptor *(*DSSI_Descriptor_Function)(unsigned long Index); | |||
/* | |||
* Macros to specify particular MIDI controllers in return values from | |||
* get_midi_controller_for_port() | |||
*/ | |||
#define DSSI_CC_BITS 0x20000000 | |||
#define DSSI_NRPN_BITS 0x40000000 | |||
#define DSSI_NONE -1 | |||
#define DSSI_CONTROLLER_IS_SET(n) (DSSI_NONE != (n)) | |||
#define DSSI_CC(n) (DSSI_CC_BITS | (n)) | |||
#define DSSI_IS_CC(n) (DSSI_CC_BITS & (n)) | |||
#define DSSI_CC_NUMBER(n) ((n) & 0x7f) | |||
#define DSSI_NRPN(n) (DSSI_NRPN_BITS | ((n) << 7)) | |||
#define DSSI_IS_NRPN(n) (DSSI_NRPN_BITS & (n)) | |||
#define DSSI_NRPN_NUMBER(n) (((n) >> 7) & 0x3fff) | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* DSSI_INCLUDED */ |
@@ -0,0 +1,272 @@ | |||
/* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the GNU Lesser General Public License as | |||
* published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public | |||
* License along with this library; if not, write to the Free Software | |||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
* | |||
*/ | |||
#ifndef __ALSA_SEQ_EVENT_COMPAT_H | |||
#define __ALSA_SEQ_EVENT_COMPAT_H | |||
/** | |||
* Sequencer event data type | |||
*/ | |||
typedef unsigned char snd_seq_event_type_t; | |||
/** Sequencer event type */ | |||
enum snd_seq_event_type { | |||
/** system status; event data type = #snd_seq_result_t */ | |||
SND_SEQ_EVENT_SYSTEM = 0, | |||
/** returned result status; event data type = #snd_seq_result_t */ | |||
SND_SEQ_EVENT_RESULT, | |||
/** note on and off with duration; event data type = #snd_seq_ev_note_t */ | |||
SND_SEQ_EVENT_NOTE = 5, | |||
/** note on; event data type = #snd_seq_ev_note_t */ | |||
SND_SEQ_EVENT_NOTEON, | |||
/** note off; event data type = #snd_seq_ev_note_t */ | |||
SND_SEQ_EVENT_NOTEOFF, | |||
/** key pressure change (aftertouch); event data type = #snd_seq_ev_note_t */ | |||
SND_SEQ_EVENT_KEYPRESS, | |||
/** controller; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_CONTROLLER = 10, | |||
/** program change; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_PGMCHANGE, | |||
/** channel pressure; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_CHANPRESS, | |||
/** pitchwheel; event data type = #snd_seq_ev_ctrl_t; data is from -8192 to 8191) */ | |||
SND_SEQ_EVENT_PITCHBEND, | |||
/** 14 bit controller value; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_CONTROL14, | |||
/** 14 bit NRPN; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_NONREGPARAM, | |||
/** 14 bit RPN; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_REGPARAM, | |||
/** SPP with LSB and MSB values; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_SONGPOS = 20, | |||
/** Song Select with song ID number; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_SONGSEL, | |||
/** midi time code quarter frame; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_QFRAME, | |||
/** SMF Time Signature event; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_TIMESIGN, | |||
/** SMF Key Signature event; event data type = #snd_seq_ev_ctrl_t */ | |||
SND_SEQ_EVENT_KEYSIGN, | |||
/** MIDI Real Time Start message; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_START = 30, | |||
/** MIDI Real Time Continue message; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_CONTINUE, | |||
/** MIDI Real Time Stop message; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_STOP, | |||
/** Set tick queue position; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_SETPOS_TICK, | |||
/** Set real-time queue position; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_SETPOS_TIME, | |||
/** (SMF) Tempo event; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_TEMPO, | |||
/** MIDI Real Time Clock message; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_CLOCK, | |||
/** MIDI Real Time Tick message; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_TICK, | |||
/** Queue timer skew; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_QUEUE_SKEW, | |||
/** Sync position changed; event data type = #snd_seq_ev_queue_control_t */ | |||
SND_SEQ_EVENT_SYNC_POS, | |||
/** Tune request; event data type = none */ | |||
SND_SEQ_EVENT_TUNE_REQUEST = 40, | |||
/** Reset to power-on state; event data type = none */ | |||
SND_SEQ_EVENT_RESET, | |||
/** Active sensing event; event data type = none */ | |||
SND_SEQ_EVENT_SENSING, | |||
/** Echo-back event; event data type = any type */ | |||
SND_SEQ_EVENT_ECHO = 50, | |||
/** OSS emulation raw event; event data type = any type */ | |||
SND_SEQ_EVENT_OSS, | |||
/** New client has connected; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_CLIENT_START = 60, | |||
/** Client has left the system; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_CLIENT_EXIT, | |||
/** Client status/info has changed; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_CLIENT_CHANGE, | |||
/** New port was created; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_PORT_START, | |||
/** Port was deleted from system; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_PORT_EXIT, | |||
/** Port status/info has changed; event data type = #snd_seq_addr_t */ | |||
SND_SEQ_EVENT_PORT_CHANGE, | |||
/** Ports connected; event data type = #snd_seq_connect_t */ | |||
SND_SEQ_EVENT_PORT_SUBSCRIBED, | |||
/** Ports disconnected; event data type = #snd_seq_connect_t */ | |||
SND_SEQ_EVENT_PORT_UNSUBSCRIBED, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR0 = 90, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR1, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR2, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR3, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR4, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR5, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR6, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR7, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR8, | |||
/** user-defined event; event data type = any (fixed size) */ | |||
SND_SEQ_EVENT_USR9, | |||
/** system exclusive data (variable length); event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_SYSEX = 130, | |||
/** error event; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_BOUNCE, | |||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_USR_VAR0 = 135, | |||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_USR_VAR1, | |||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_USR_VAR2, | |||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_USR_VAR3, | |||
/** reserved for user apps; event data type = #snd_seq_ev_ext_t */ | |||
SND_SEQ_EVENT_USR_VAR4, | |||
/** NOP; ignored in any case */ | |||
SND_SEQ_EVENT_NONE = 255 | |||
}; | |||
/** Sequencer event address */ | |||
typedef struct snd_seq_addr { | |||
unsigned char client; /**< Client id */ | |||
unsigned char port; /**< Port id */ | |||
} snd_seq_addr_t; | |||
/** Connection (subscription) between ports */ | |||
typedef struct snd_seq_connect { | |||
snd_seq_addr_t sender; /**< sender address */ | |||
snd_seq_addr_t dest; /**< destination address */ | |||
} snd_seq_connect_t; | |||
/** Real-time data record */ | |||
typedef struct snd_seq_real_time { | |||
unsigned int tv_sec; /**< seconds */ | |||
unsigned int tv_nsec; /**< nanoseconds */ | |||
} snd_seq_real_time_t; | |||
/** (MIDI) Tick-time data record */ | |||
typedef unsigned int snd_seq_tick_time_t; | |||
/** unioned time stamp */ | |||
typedef union snd_seq_timestamp { | |||
snd_seq_tick_time_t tick; /**< tick-time */ | |||
struct snd_seq_real_time time; /**< real-time */ | |||
} snd_seq_timestamp_t; | |||
/** Note event */ | |||
typedef struct snd_seq_ev_note { | |||
unsigned char channel; /**< channel number */ | |||
unsigned char note; /**< note */ | |||
unsigned char velocity; /**< velocity */ | |||
unsigned char off_velocity; /**< note-off velocity; only for #SND_SEQ_EVENT_NOTE */ | |||
unsigned int duration; /**< duration until note-off; only for #SND_SEQ_EVENT_NOTE */ | |||
} snd_seq_ev_note_t; | |||
/** Controller event */ | |||
typedef struct snd_seq_ev_ctrl { | |||
unsigned char channel; /**< channel number */ | |||
unsigned char unused[3]; /**< reserved */ | |||
unsigned int param; /**< control parameter */ | |||
signed int value; /**< control value */ | |||
} snd_seq_ev_ctrl_t; | |||
/** generic set of bytes (12x8 bit) */ | |||
typedef struct snd_seq_ev_raw8 { | |||
unsigned char d[12]; /**< 8 bit value */ | |||
} snd_seq_ev_raw8_t; | |||
/** generic set of integers (3x32 bit) */ | |||
typedef struct snd_seq_ev_raw32 { | |||
unsigned int d[3]; /**< 32 bit value */ | |||
} snd_seq_ev_raw32_t; | |||
/** external stored data */ | |||
typedef struct snd_seq_ev_ext { | |||
unsigned int len; /**< length of data */ | |||
void *ptr; /**< pointer to data (note: can be 64-bit) */ | |||
} __attribute__((packed)) snd_seq_ev_ext_t; | |||
/** Result events */ | |||
typedef struct snd_seq_result { | |||
int event; /**< processed event type */ | |||
int result; /**< status */ | |||
} snd_seq_result_t; | |||
/** Queue skew values */ | |||
typedef struct snd_seq_queue_skew { | |||
unsigned int value; /**< skew value */ | |||
unsigned int base; /**< skew base */ | |||
} snd_seq_queue_skew_t; | |||
/** queue timer control */ | |||
typedef struct snd_seq_ev_queue_control { | |||
unsigned char queue; /**< affected queue */ | |||
unsigned char unused[3]; /**< reserved */ | |||
union { | |||
signed int value; /**< affected value (e.g. tempo) */ | |||
snd_seq_timestamp_t time; /**< time */ | |||
unsigned int position; /**< sync position */ | |||
snd_seq_queue_skew_t skew; /**< queue skew */ | |||
unsigned int d32[2]; /**< any data */ | |||
unsigned char d8[8]; /**< any data */ | |||
} param; /**< data value union */ | |||
} snd_seq_ev_queue_control_t; | |||
/** Sequencer event */ | |||
typedef struct snd_seq_event { | |||
snd_seq_event_type_t type; /**< event type */ | |||
unsigned char flags; /**< event flags */ | |||
unsigned char tag; /**< tag */ | |||
unsigned char queue; /**< schedule queue */ | |||
snd_seq_timestamp_t time; /**< schedule time */ | |||
snd_seq_addr_t source; /**< source address */ | |||
snd_seq_addr_t dest; /**< destination address */ | |||
union { | |||
snd_seq_ev_note_t note; /**< note information */ | |||
snd_seq_ev_ctrl_t control; /**< MIDI control information */ | |||
snd_seq_ev_raw8_t raw8; /**< raw8 data */ | |||
snd_seq_ev_raw32_t raw32; /**< raw32 data */ | |||
snd_seq_ev_ext_t ext; /**< external data */ | |||
snd_seq_ev_queue_control_t queue; /**< queue control */ | |||
snd_seq_timestamp_t time; /**< timestamp */ | |||
snd_seq_addr_t addr; /**< address */ | |||
snd_seq_connect_t connect; /**< connect information */ | |||
snd_seq_result_t result; /**< operation result code */ | |||
} data; /**< event data... */ | |||
} snd_seq_event_t; | |||
#endif /* __ALSA_SEQ_EVENT_COMPAT_H */ | |||
@@ -0,0 +1,603 @@ | |||
/* ladspa.h | |||
Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. | |||
Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, | |||
Stefan Westerfeld. | |||
This library is free software; you can redistribute it and/or | |||
modify it under the terms of the GNU Lesser General Public License | |||
as published by the Free Software Foundation; either version 2.1 of | |||
the License, or (at your option) any later version. | |||
This library 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 | |||
Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with this library; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | |||
USA. */ | |||
#ifndef LADSPA_INCLUDED | |||
#define LADSPA_INCLUDED | |||
#define LADSPA_VERSION "1.1" | |||
#define LADSPA_VERSION_MAJOR 1 | |||
#define LADSPA_VERSION_MINOR 1 | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/*****************************************************************************/ | |||
/* Overview: | |||
There is a large number of synthesis packages in use or development | |||
on the Linux platform at this time. This API (`The Linux Audio | |||
Developer's Simple Plugin API') attempts to give programmers the | |||
ability to write simple `plugin' audio processors in C/C++ and link | |||
them dynamically (`plug') into a range of these packages (`hosts'). | |||
It should be possible for any host and any plugin to communicate | |||
completely through this interface. | |||
This API is deliberately short and simple. To achieve compatibility | |||
with a range of promising Linux sound synthesis packages it | |||
attempts to find the `greatest common divisor' in their logical | |||
behaviour. Having said this, certain limiting decisions are | |||
implicit, notably the use of a fixed type (LADSPA_Data) for all | |||
data transfer and absence of a parameterised `initialisation' | |||
phase. See below for the LADSPA_Data typedef. | |||
Plugins are expected to distinguish between control and audio | |||
data. Plugins have `ports' that are inputs or outputs for audio or | |||
control data and each plugin is `run' for a `block' corresponding | |||
to a short time interval measured in samples. Audio data is | |||
communicated using arrays of LADSPA_Data, allowing a block of audio | |||
to be processed by the plugin in a single pass. Control data is | |||
communicated using single LADSPA_Data values. Control data has a | |||
single value at the start of a call to the `run()' or `run_adding()' | |||
function, and may be considered to remain this value for its | |||
duration. The plugin may assume that all its input and output ports | |||
have been connected to the relevant data location (see the | |||
`connect_port()' function below) before it is asked to run. | |||
Plugins will reside in shared object files suitable for dynamic | |||
linking by dlopen() and family. The file will provide a number of | |||
`plugin types' that can be used to instantiate actual plugins | |||
(sometimes known as `plugin instances') that can be connected | |||
together to perform tasks. | |||
This API contains very limited error-handling. */ | |||
/*****************************************************************************/ | |||
/* Fundamental data type passed in and out of plugin. This data type | |||
is used to communicate audio samples and control values. It is | |||
assumed that the plugin will work sensibly given any numeric input | |||
value although it may have a preferred range (see hints below). | |||
For audio it is generally assumed that 1.0f is the `0dB' reference | |||
amplitude and is a `normal' signal level. */ | |||
typedef float LADSPA_Data; | |||
/*****************************************************************************/ | |||
/* Special Plugin Properties: | |||
Optional features of the plugin type are encapsulated in the | |||
LADSPA_Properties type. This is assembled by ORing individual | |||
properties together. */ | |||
typedef int LADSPA_Properties; | |||
/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a | |||
real-time dependency (e.g. listens to a MIDI device) and so its | |||
output must not be cached or subject to significant latency. */ | |||
#define LADSPA_PROPERTY_REALTIME 0x1 | |||
/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin | |||
may cease to work correctly if the host elects to use the same data | |||
location for both input and output (see connect_port()). This | |||
should be avoided as enabling this flag makes it impossible for | |||
hosts to use the plugin to process audio `in-place.' */ | |||
#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 | |||
/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin | |||
is capable of running not only in a conventional host but also in a | |||
`hard real-time' environment. To qualify for this the plugin must | |||
satisfy all of the following: | |||
(1) The plugin must not use malloc(), free() or other heap memory | |||
management within its run() or run_adding() functions. All new | |||
memory used in run() must be managed via the stack. These | |||
restrictions only apply to the run() function. | |||
(2) The plugin will not attempt to make use of any library | |||
functions with the exceptions of functions in the ANSI standard C | |||
and C maths libraries, which the host is expected to provide. | |||
(3) The plugin will not access files, devices, pipes, sockets, IPC | |||
or any other mechanism that might result in process or thread | |||
blocking. | |||
(4) The plugin will take an amount of time to execute a run() or | |||
run_adding() call approximately of form (A+B*SampleCount) where A | |||
and B depend on the machine and host in use. This amount of time | |||
may not depend on input signals or plugin state. The host is left | |||
the responsibility to perform timings to estimate upper bounds for | |||
A and B. */ | |||
#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 | |||
#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) | |||
#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) | |||
#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) | |||
/*****************************************************************************/ | |||
/* Plugin Ports: | |||
Plugins have `ports' that are inputs or outputs for audio or | |||
data. Ports can communicate arrays of LADSPA_Data (for audio | |||
inputs/outputs) or single LADSPA_Data values (for control | |||
input/outputs). This information is encapsulated in the | |||
LADSPA_PortDescriptor type which is assembled by ORing individual | |||
properties together. | |||
Note that a port must be an input or an output port but not both | |||
and that a port must be a control or audio port but not both. */ | |||
typedef int LADSPA_PortDescriptor; | |||
/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ | |||
#define LADSPA_PORT_INPUT 0x1 | |||
/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ | |||
#define LADSPA_PORT_OUTPUT 0x2 | |||
/* Property LADSPA_PORT_CONTROL indicates that the port is a control | |||
port. */ | |||
#define LADSPA_PORT_CONTROL 0x4 | |||
/* Property LADSPA_PORT_AUDIO indicates that the port is a audio | |||
port. */ | |||
#define LADSPA_PORT_AUDIO 0x8 | |||
#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) | |||
#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) | |||
#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) | |||
#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) | |||
/*****************************************************************************/ | |||
/* Plugin Port Range Hints: | |||
The host may wish to provide a representation of data entering or | |||
leaving a plugin (e.g. to generate a GUI automatically). To make | |||
this more meaningful, the plugin should provide `hints' to the host | |||
describing the usual values taken by the data. | |||
Note that these are only hints. The host may ignore them and the | |||
plugin must not assume that data supplied to it is meaningful. If | |||
the plugin receives invalid input data it is expected to continue | |||
to run without failure and, where possible, produce a sensible | |||
output (e.g. a high-pass filter given a negative cutoff frequency | |||
might switch to an all-pass mode). | |||
Hints are meaningful for all input and output ports but hints for | |||
input control ports are expected to be particularly useful. | |||
More hint information is encapsulated in the | |||
LADSPA_PortRangeHintDescriptor type which is assembled by ORing | |||
individual hint types together. Hints may require further | |||
LowerBound and UpperBound information. | |||
All the hint information for a particular port is aggregated in the | |||
LADSPA_PortRangeHint structure. */ | |||
typedef int LADSPA_PortRangeHintDescriptor; | |||
/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field | |||
of the LADSPA_PortRangeHint should be considered meaningful. The | |||
value in this field should be considered the (inclusive) lower | |||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also | |||
specified then the value of LowerBound should be multiplied by the | |||
sample rate. */ | |||
#define LADSPA_HINT_BOUNDED_BELOW 0x1 | |||
/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field | |||
of the LADSPA_PortRangeHint should be considered meaningful. The | |||
value in this field should be considered the (inclusive) upper | |||
bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also | |||
specified then the value of UpperBound should be multiplied by the | |||
sample rate. */ | |||
#define LADSPA_HINT_BOUNDED_ABOVE 0x2 | |||
/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be | |||
considered a Boolean toggle. Data less than or equal to zero should | |||
be considered `off' or `false,' and data above zero should be | |||
considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in | |||
conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or | |||
LADSPA_HINT_DEFAULT_1. */ | |||
#define LADSPA_HINT_TOGGLED 0x4 | |||
/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified | |||
should be interpreted as multiples of the sample rate. For | |||
instance, a frequency range from 0Hz to the Nyquist frequency (half | |||
the sample rate) could be requested by this hint in conjunction | |||
with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds | |||
at all must support this hint to retain meaning. */ | |||
#define LADSPA_HINT_SAMPLE_RATE 0x8 | |||
/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the | |||
user will find it more intuitive to view values using a logarithmic | |||
scale. This is particularly useful for frequencies and gains. */ | |||
#define LADSPA_HINT_LOGARITHMIC 0x10 | |||
/* Hint LADSPA_HINT_INTEGER indicates that a user interface would | |||
probably wish to provide a stepped control taking only integer | |||
values. Any bounds set should be slightly wider than the actual | |||
integer range required to avoid floating point rounding errors. For | |||
instance, the integer set {0,1,2,3} might be described as [-0.1, | |||
3.1]. */ | |||
#define LADSPA_HINT_INTEGER 0x20 | |||
/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' | |||
value for the port that is sensible as a default. For instance, | |||
this value is suitable for use as an initial value in a user | |||
interface or as a value the host might assign to a control port | |||
when the user has not provided one. Defaults are encoded using a | |||
mask so only one default may be specified for a port. Some of the | |||
hints make use of lower and upper bounds, in which case the | |||
relevant bound or bounds must be available and | |||
LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting | |||
default must be rounded if LADSPA_HINT_INTEGER is present. Default | |||
values were introduced in LADSPA v1.1. */ | |||
#define LADSPA_HINT_DEFAULT_MASK 0x3C0 | |||
/* This default values indicates that no default is provided. */ | |||
#define LADSPA_HINT_DEFAULT_NONE 0x0 | |||
/* This default hint indicates that the suggested lower bound for the | |||
port should be used. */ | |||
#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 | |||
/* This default hint indicates that a low value between the suggested | |||
lower and upper bounds should be chosen. For ports with | |||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + | |||
log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper | |||
* 0.25). */ | |||
#define LADSPA_HINT_DEFAULT_LOW 0x80 | |||
/* This default hint indicates that a middle value between the | |||
suggested lower and upper bounds should be chosen. For ports with | |||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + | |||
log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * | |||
0.5). */ | |||
#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 | |||
/* This default hint indicates that a high value between the suggested | |||
lower and upper bounds should be chosen. For ports with | |||
LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + | |||
log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper | |||
* 0.75). */ | |||
#define LADSPA_HINT_DEFAULT_HIGH 0x100 | |||
/* This default hint indicates that the suggested upper bound for the | |||
port should be used. */ | |||
#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 | |||
/* This default hint indicates that the number 0 should be used. Note | |||
that this default may be used in conjunction with | |||
LADSPA_HINT_TOGGLED. */ | |||
#define LADSPA_HINT_DEFAULT_0 0x200 | |||
/* This default hint indicates that the number 1 should be used. Note | |||
that this default may be used in conjunction with | |||
LADSPA_HINT_TOGGLED. */ | |||
#define LADSPA_HINT_DEFAULT_1 0x240 | |||
/* This default hint indicates that the number 100 should be used. */ | |||
#define LADSPA_HINT_DEFAULT_100 0x280 | |||
/* This default hint indicates that the Hz frequency of `concert A' | |||
should be used. This will be 440 unless the host uses an unusual | |||
tuning convention, in which case it may be within a few Hz. */ | |||
#define LADSPA_HINT_DEFAULT_440 0x2C0 | |||
#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) | |||
#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) | |||
#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) | |||
#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) | |||
#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) | |||
#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) | |||
#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) | |||
#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_MINIMUM) | |||
#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_LOW) | |||
#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_MIDDLE) | |||
#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_HIGH) | |||
#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_MAXIMUM) | |||
#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_0) | |||
#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_1) | |||
#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_100) | |||
#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ | |||
== LADSPA_HINT_DEFAULT_440) | |||
typedef struct _LADSPA_PortRangeHint { | |||
/* Hints about the port. */ | |||
LADSPA_PortRangeHintDescriptor HintDescriptor; | |||
/* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When | |||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be | |||
multiplied by the relevant sample rate. */ | |||
LADSPA_Data LowerBound; | |||
/* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When | |||
LADSPA_HINT_SAMPLE_RATE is also active then this value should be | |||
multiplied by the relevant sample rate. */ | |||
LADSPA_Data UpperBound; | |||
} LADSPA_PortRangeHint; | |||
/*****************************************************************************/ | |||
/* Plugin Handles: | |||
This plugin handle indicates a particular instance of the plugin | |||
concerned. It is valid to compare this to NULL (0 for C++) but | |||
otherwise the host should not attempt to interpret it. The plugin | |||
may use it to reference internal instance data. */ | |||
typedef void * LADSPA_Handle; | |||
/*****************************************************************************/ | |||
/* Descriptor for a Type of Plugin: | |||
This structure is used to describe a plugin type. It provides a | |||
number of functions to examine the type, instantiate it, link it to | |||
buffers and workspaces and to run it. */ | |||
typedef struct _LADSPA_Descriptor { | |||
/* This numeric identifier indicates the plugin type | |||
uniquely. Plugin programmers may reserve ranges of IDs from a | |||
central body to avoid clashes. Hosts may assume that IDs are | |||
below 0x1000000. */ | |||
unsigned long UniqueID; | |||
/* This identifier can be used as a unique, case-sensitive | |||
identifier for the plugin type within the plugin file. Plugin | |||
types should be identified by file and label rather than by index | |||
or plugin name, which may be changed in new plugin | |||
versions. Labels must not contain white-space characters. */ | |||
const char * Label; | |||
/* This indicates a number of properties of the plugin. */ | |||
LADSPA_Properties Properties; | |||
/* This member points to the null-terminated name of the plugin | |||
(e.g. "Sine Oscillator"). */ | |||
const char * Name; | |||
/* This member points to the null-terminated string indicating the | |||
maker of the plugin. This can be an empty string but not NULL. */ | |||
const char * Maker; | |||
/* This member points to the null-terminated string indicating any | |||
copyright applying to the plugin. If no Copyright applies the | |||
string "None" should be used. */ | |||
const char * Copyright; | |||
/* This indicates the number of ports (input AND output) present on | |||
the plugin. */ | |||
unsigned long PortCount; | |||
/* This member indicates an array of port descriptors. Valid indices | |||
vary from 0 to PortCount-1. */ | |||
const LADSPA_PortDescriptor * PortDescriptors; | |||
/* This member indicates an array of null-terminated strings | |||
describing ports (e.g. "Frequency (Hz)"). Valid indices vary from | |||
0 to PortCount-1. */ | |||
const char * const * PortNames; | |||
/* This member indicates an array of range hints for each port (see | |||
above). Valid indices vary from 0 to PortCount-1. */ | |||
const LADSPA_PortRangeHint * PortRangeHints; | |||
/* This may be used by the plugin developer to pass any custom | |||
implementation data into an instantiate call. It must not be used | |||
or interpreted by the host. It is expected that most plugin | |||
writers will not use this facility as LADSPA_Handle should be | |||
used to hold instance data. */ | |||
void * ImplementationData; | |||
/* This member is a function pointer that instantiates a plugin. A | |||
handle is returned indicating the new plugin instance. The | |||
instantiation function accepts a sample rate as a parameter. The | |||
plugin descriptor from which this instantiate function was found | |||
must also be passed. This function must return NULL if | |||
instantiation fails. | |||
Note that instance initialisation should generally occur in | |||
activate() rather than here. */ | |||
LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, | |||
unsigned long SampleRate); | |||
/* This member is a function pointer that connects a port on an | |||
instantiated plugin to a memory location at which a block of data | |||
for the port will be read/written. The data location is expected | |||
to be an array of LADSPA_Data for audio ports or a single | |||
LADSPA_Data value for control ports. Memory issues will be | |||
managed by the host. The plugin must read/write the data at these | |||
locations every time run() or run_adding() is called and the data | |||
present at the time of this connection call should not be | |||
considered meaningful. | |||
connect_port() may be called more than once for a plugin instance | |||
to allow the host to change the buffers that the plugin is | |||
reading or writing. These calls may be made before or after | |||
activate() or deactivate() calls. | |||
connect_port() must be called at least once for each port before | |||
run() or run_adding() is called. When working with blocks of | |||
LADSPA_Data the plugin should pay careful attention to the block | |||
size passed to the run function as the block allocated may only | |||
just be large enough to contain the block of samples. | |||
Plugin writers should be aware that the host may elect to use the | |||
same buffer for more than one port and even use the same buffer | |||
for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). | |||
However, overlapped buffers or use of a single buffer for both | |||
audio and control data may result in unexpected behaviour. */ | |||
void (*connect_port)(LADSPA_Handle Instance, | |||
unsigned long Port, | |||
LADSPA_Data * DataLocation); | |||
/* This member is a function pointer that initialises a plugin | |||
instance and activates it for use. This is separated from | |||
instantiate() to aid real-time support and so that hosts can | |||
reinitialise a plugin instance by calling deactivate() and then | |||
activate(). In this case the plugin instance must reset all state | |||
information dependent on the history of the plugin instance | |||
except for any data locations provided by connect_port() and any | |||
gain set by set_run_adding_gain(). If there is nothing for | |||
activate() to do then the plugin writer may provide a NULL rather | |||
than an empty function. | |||
When present, hosts must call this function once before run() (or | |||
run_adding()) is called for the first time. This call should be | |||
made as close to the run() call as possible and indicates to | |||
real-time plugins that they are now live. Plugins should not rely | |||
on a prompt call to run() after activate(). activate() may not be | |||
called again unless deactivate() is called first. Note that | |||
connect_port() may be called before or after a call to | |||
activate(). */ | |||
void (*activate)(LADSPA_Handle Instance); | |||
/* This method is a function pointer that runs an instance of a | |||
plugin for a block. Two parameters are required: the first is a | |||
handle to the particular instance to be run and the second | |||
indicates the block size (in samples) for which the plugin | |||
instance may run. | |||
Note that if an activate() function exists then it must be called | |||
before run() or run_adding(). If deactivate() is called for a | |||
plugin instance then the plugin instance may not be reused until | |||
activate() has been called again. | |||
If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE | |||
then there are various things that the plugin should not do | |||
within the run() or run_adding() functions (see above). */ | |||
void (*run)(LADSPA_Handle Instance, | |||
unsigned long SampleCount); | |||
/* This method is a function pointer that runs an instance of a | |||
plugin for a block. This has identical behaviour to run() except | |||
in the way data is output from the plugin. When run() is used, | |||
values are written directly to the memory areas associated with | |||
the output ports. However when run_adding() is called, values | |||
must be added to the values already present in the memory | |||
areas. Furthermore, output values written must be scaled by the | |||
current gain set by set_run_adding_gain() (see below) before | |||
addition. | |||
run_adding() is optional. When it is not provided by a plugin, | |||
this function pointer must be set to NULL. When it is provided, | |||
the function set_run_adding_gain() must be provided also. */ | |||
void (*run_adding)(LADSPA_Handle Instance, | |||
unsigned long SampleCount); | |||
/* This method is a function pointer that sets the output gain for | |||
use when run_adding() is called (see above). If this function is | |||
never called the gain is assumed to default to 1. Gain | |||
information should be retained when activate() or deactivate() | |||
are called. | |||
This function should be provided by the plugin if and only if the | |||
run_adding() function is provided. When it is absent this | |||
function pointer must be set to NULL. */ | |||
void (*set_run_adding_gain)(LADSPA_Handle Instance, | |||
LADSPA_Data Gain); | |||
/* This is the counterpart to activate() (see above). If there is | |||
nothing for deactivate() to do then the plugin writer may provide | |||
a NULL rather than an empty function. | |||
Hosts must deactivate all activated units after they have been | |||
run() (or run_adding()) for the last time. This call should be | |||
made as close to the last run() call as possible and indicates to | |||
real-time plugins that they are no longer live. Plugins should | |||
not rely on prompt deactivation. Note that connect_port() may be | |||
called before or after a call to deactivate(). | |||
Deactivation is not similar to pausing as the plugin instance | |||
will be reinitialised when activate() is called to reuse it. */ | |||
void (*deactivate)(LADSPA_Handle Instance); | |||
/* Once an instance of a plugin has been finished with it can be | |||
deleted using the following function. The instance handle passed | |||
ceases to be valid after this call. | |||
If activate() was called for a plugin instance then a | |||
corresponding call to deactivate() must be made before cleanup() | |||
is called. */ | |||
void (*cleanup)(LADSPA_Handle Instance); | |||
} LADSPA_Descriptor; | |||
/**********************************************************************/ | |||
/* Accessing a Plugin: */ | |||
/* The exact mechanism by which plugins are loaded is host-dependent, | |||
however all most hosts will need to know is the name of shared | |||
object file containing the plugin types. To allow multiple hosts to | |||
share plugin types, hosts may wish to check for environment | |||
variable LADSPA_PATH. If present, this should contain a | |||
colon-separated path indicating directories that should be searched | |||
(in order) when loading plugin types. | |||
A plugin programmer must include a function called | |||
"ladspa_descriptor" with the following function prototype within | |||
the shared object file. This function will have C-style linkage (if | |||
you are using C++ this is taken care of by the `extern "C"' clause | |||
at the top of the file). | |||
A host will find the plugin shared object file by one means or | |||
another, find the ladspa_descriptor() function, call it, and | |||
proceed from there. | |||
Plugin types are accessed by index (not ID) using values from 0 | |||
upwards. Out of range indexes must result in this function | |||
returning NULL, so the plugin count can be determined by checking | |||
for the least index that results in NULL being returned. */ | |||
const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); | |||
/* Datatype corresponding to the ladspa_descriptor() function. */ | |||
typedef const LADSPA_Descriptor * | |||
(*LADSPA_Descriptor_Function)(unsigned long Index); | |||
/**********************************************************************/ | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* LADSPA_INCLUDED */ | |||
/* EOF */ |
@@ -0,0 +1,619 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file forge.h An API for constructing LV2 atoms. | |||
This file provides an API for constructing Atoms which makes it relatively | |||
simple to build nested atoms of arbitrary complexity without requiring | |||
dynamic memory allocation. | |||
The API is based on successively appending the appropriate pieces to build a | |||
complete Atom. The size of containers is automatically updated. Functions | |||
that begin a container return (via their frame argument) a stack frame which | |||
must be popped when the container is finished. | |||
All output is written to a user-provided buffer or sink function. This | |||
makes it popssible to create create atoms on the stack, on the heap, in LV2 | |||
port buffers, in a ringbuffer, or elsewhere, all using the same API. | |||
This entire API is realtime safe if used with a buffer or a realtime safe | |||
sink, except lv2_atom_forge_init() which is only realtime safe if the URI | |||
map function is. | |||
Note these functions are all static inline, do not take their address. | |||
This header is non-normative, it is provided for convenience. | |||
*/ | |||
#ifndef LV2_ATOM_FORGE_H | |||
#define LV2_ATOM_FORGE_H | |||
#include <assert.h> | |||
#include "atom.h" | |||
#include "atom-util.h" | |||
#include "urid.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** Handle for LV2_Atom_Forge_Sink. */ | |||
typedef void* LV2_Atom_Forge_Sink_Handle; | |||
/** A reference to a chunk of written output. */ | |||
typedef intptr_t LV2_Atom_Forge_Ref; | |||
/** Sink function for writing output. See lv2_atom_forge_set_sink(). */ | |||
typedef LV2_Atom_Forge_Ref | |||
(*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle, | |||
const void* buf, | |||
uint32_t size); | |||
/** Function for resolving a reference. See lv2_atom_forge_set_sink(). */ | |||
typedef LV2_Atom* | |||
(*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle, | |||
LV2_Atom_Forge_Ref ref); | |||
/** A stack frame used for keeping track of nested Atom containers. */ | |||
typedef struct _LV2_Atom_Forge_Frame { | |||
struct _LV2_Atom_Forge_Frame* parent; | |||
LV2_Atom_Forge_Ref ref; | |||
} LV2_Atom_Forge_Frame; | |||
/** A "forge" for creating atoms by appending to a buffer. */ | |||
typedef struct { | |||
uint8_t* buf; | |||
uint32_t offset; | |||
uint32_t size; | |||
LV2_Atom_Forge_Sink sink; | |||
LV2_Atom_Forge_Deref_Func deref; | |||
LV2_Atom_Forge_Sink_Handle handle; | |||
LV2_Atom_Forge_Frame* stack; | |||
LV2_URID Blank; | |||
LV2_URID Bool; | |||
LV2_URID Chunk; | |||
LV2_URID Double; | |||
LV2_URID Float; | |||
LV2_URID Int; | |||
LV2_URID Long; | |||
LV2_URID Literal; | |||
LV2_URID Path; | |||
LV2_URID Property; | |||
LV2_URID Resource; | |||
LV2_URID Sequence; | |||
LV2_URID String; | |||
LV2_URID Tuple; | |||
LV2_URID URI; | |||
LV2_URID URID; | |||
LV2_URID Vector; | |||
} LV2_Atom_Forge; | |||
static inline void | |||
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size); | |||
/** | |||
Initialise @p forge. | |||
URIs will be mapped using @p map and stored, a reference to @p map itself is | |||
not held. | |||
*/ | |||
static inline void | |||
lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) | |||
{ | |||
lv2_atom_forge_set_buffer(forge, NULL, 0); | |||
forge->Blank = map->map(map->handle, LV2_ATOM__Blank); | |||
forge->Bool = map->map(map->handle, LV2_ATOM__Bool); | |||
forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk); | |||
forge->Double = map->map(map->handle, LV2_ATOM__Double); | |||
forge->Float = map->map(map->handle, LV2_ATOM__Float); | |||
forge->Int = map->map(map->handle, LV2_ATOM__Int); | |||
forge->Long = map->map(map->handle, LV2_ATOM__Long); | |||
forge->Literal = map->map(map->handle, LV2_ATOM__Literal); | |||
forge->Path = map->map(map->handle, LV2_ATOM__Path); | |||
forge->Property = map->map(map->handle, LV2_ATOM__Property); | |||
forge->Resource = map->map(map->handle, LV2_ATOM__Resource); | |||
forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence); | |||
forge->String = map->map(map->handle, LV2_ATOM__String); | |||
forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple); | |||
forge->URI = map->map(map->handle, LV2_ATOM__URI); | |||
forge->URID = map->map(map->handle, LV2_ATOM__URID); | |||
forge->Vector = map->map(map->handle, LV2_ATOM__Vector); | |||
} | |||
static inline LV2_Atom* | |||
lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref) | |||
{ | |||
if (forge->buf) { | |||
return (LV2_Atom*)ref; | |||
} else { | |||
return forge->deref(forge->handle, ref); | |||
} | |||
} | |||
/** | |||
@name Object Stack | |||
@{ | |||
*/ | |||
/** | |||
Push a stack frame. | |||
This is done automatically by container functions (which take a stack frame | |||
pointer), but may be called by the user to push the top level container when | |||
writing to an existing Atom. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_push(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Frame* frame, | |||
LV2_Atom_Forge_Ref ref) | |||
{ | |||
frame->parent = forge->stack; | |||
frame->ref = ref; | |||
forge->stack = frame; | |||
return ref; | |||
} | |||
/** Pop a stack frame. This must be called when a container is finished. */ | |||
static inline void | |||
lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) | |||
{ | |||
assert(frame == forge->stack); | |||
forge->stack = frame->parent; | |||
} | |||
/** Return true iff the top of the stack has the given type. */ | |||
static inline bool | |||
lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type) | |||
{ | |||
return forge->stack && | |||
lv2_atom_forge_deref(forge, forge->stack->ref)->type == type; | |||
} | |||
/** | |||
@} | |||
@name Output Configuration | |||
@{ | |||
*/ | |||
/** Set the output buffer where @p forge will write atoms. */ | |||
static inline void | |||
lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) | |||
{ | |||
forge->buf = buf; | |||
forge->size = size; | |||
forge->offset = 0; | |||
forge->deref = NULL; | |||
forge->sink = NULL; | |||
forge->handle = NULL; | |||
forge->stack = NULL; | |||
} | |||
/** | |||
Set the sink function where @p forge will write output. | |||
The return value of forge functions is an LV2_Atom_Forge_Ref which is an | |||
integer type safe to use as a pointer but is otherwise opaque. The sink | |||
function must return a ref that can be dereferenced to access as least | |||
sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For | |||
ringbuffers, this should be possible as long as the size of the buffer is a | |||
multiple of sizeof(LV2_Atom), since atoms are always aligned. | |||
Note that 0 is an invalid reference, so if you are using a buffer offset be | |||
sure to offset it such that 0 is never a valid reference. You will get | |||
confusing errors otherwise. | |||
*/ | |||
static inline void | |||
lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Sink sink, | |||
LV2_Atom_Forge_Deref_Func deref, | |||
LV2_Atom_Forge_Sink_Handle handle) | |||
{ | |||
forge->buf = NULL; | |||
forge->size = forge->offset = 0; | |||
forge->deref = deref; | |||
forge->sink = sink; | |||
forge->handle = handle; | |||
forge->stack = NULL; | |||
} | |||
/** | |||
@} | |||
@name Low Level Output | |||
@{ | |||
*/ | |||
/** | |||
Write raw output. This is used internally, but is also useful for writing | |||
atom types not explicitly supported by the forge API. Note the caller is | |||
responsible for ensuring the output is approriately padded. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size) | |||
{ | |||
LV2_Atom_Forge_Ref out = 0; | |||
if (forge->sink) { | |||
out = forge->sink(forge->handle, data, size); | |||
} else { | |||
out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset; | |||
uint8_t* mem = forge->buf + forge->offset; | |||
if (forge->offset + size > forge->size) { | |||
return 0; | |||
} | |||
forge->offset += size; | |||
memcpy(mem, data, size); | |||
} | |||
for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) { | |||
lv2_atom_forge_deref(forge, f->ref)->size += size; | |||
} | |||
return out; | |||
} | |||
/** Pad output accordingly so next write is 64-bit aligned. */ | |||
static inline void | |||
lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written) | |||
{ | |||
const uint64_t pad = 0; | |||
const uint32_t pad_size = lv2_atom_pad_size(written) - written; | |||
lv2_atom_forge_raw(forge, &pad, pad_size); | |||
} | |||
/** Write raw output, padding to 64-bits as necessary. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size) | |||
{ | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size); | |||
if (out) { | |||
lv2_atom_forge_pad(forge, size); | |||
} | |||
return out; | |||
} | |||
/** Write a null-terminated string body. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_string_body(LV2_Atom_Forge* forge, | |||
const char* str, | |||
uint32_t len) | |||
{ | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len); | |||
if (out && (out = lv2_atom_forge_raw(forge, "", 1))) { | |||
lv2_atom_forge_pad(forge, len + 1); | |||
} | |||
return out; | |||
} | |||
/** | |||
@} | |||
@name Atom Output | |||
@{ | |||
*/ | |||
/** Write an atom:Atom header. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type) | |||
{ | |||
const LV2_Atom a = { size, type }; | |||
return lv2_atom_forge_raw(forge, &a, sizeof(a)); | |||
} | |||
/** Write a primitive (fixed-size) atom. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a) | |||
{ | |||
if (lv2_atom_forge_top_is(forge, forge->Vector)) { | |||
return lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size); | |||
} else { | |||
return lv2_atom_forge_write(forge, a, sizeof(LV2_Atom) + a->size); | |||
} | |||
} | |||
/** Write an atom:Int. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val) | |||
{ | |||
const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom:Long. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val) | |||
{ | |||
const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom:Float. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_float(LV2_Atom_Forge* forge, float val) | |||
{ | |||
const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom:Double. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_double(LV2_Atom_Forge* forge, double val) | |||
{ | |||
const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom:Bool. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val) | |||
{ | |||
const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom:URID. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id) | |||
{ | |||
const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id }; | |||
return lv2_atom_forge_primitive(forge, &a.atom); | |||
} | |||
/** Write an atom compatible with atom:String. Used internally. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, | |||
uint32_t type, | |||
const char* str, | |||
uint32_t len) | |||
{ | |||
const LV2_Atom_String a = { { len + 1, type } }; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); | |||
if (out) { | |||
if (!lv2_atom_forge_string_body(forge, str, len)) { | |||
LV2_Atom* atom = lv2_atom_forge_deref(forge, out); | |||
atom->size = atom->type = 0; | |||
out = 0; | |||
} | |||
} | |||
return out; | |||
} | |||
/** Write an atom:String. Note that @p str need not be NULL terminated. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) | |||
{ | |||
return lv2_atom_forge_typed_string(forge, forge->String, str, len); | |||
} | |||
/** | |||
Write an atom:URI. Note that @p uri need not be NULL terminated. | |||
This does not map the URI, but writes the complete URI string. To write | |||
a mapped URI, use lv2_atom_forge_urid(). | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len) | |||
{ | |||
return lv2_atom_forge_typed_string(forge, forge->URI, uri, len); | |||
} | |||
/** Write an atom:Path. Note that @p path need not be NULL terminated. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len) | |||
{ | |||
return lv2_atom_forge_typed_string(forge, forge->Path, path, len); | |||
} | |||
/** Write an atom:Literal. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_literal(LV2_Atom_Forge* forge, | |||
const char* str, | |||
uint32_t len, | |||
uint32_t datatype, | |||
uint32_t lang) | |||
{ | |||
const LV2_Atom_Literal a = { | |||
{ (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1), | |||
forge->Literal }, | |||
{ datatype, | |||
lang } | |||
}; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); | |||
if (out) { | |||
if (!lv2_atom_forge_string_body(forge, str, len)) { | |||
LV2_Atom* atom = lv2_atom_forge_deref(forge, out); | |||
atom->size = atom->type = 0; | |||
out = 0; | |||
} | |||
} | |||
return out; | |||
} | |||
/** Start an atom:Vector. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Frame* frame, | |||
uint32_t child_size, | |||
uint32_t child_type) | |||
{ | |||
const LV2_Atom_Vector a = { | |||
{ sizeof(LV2_Atom_Vector_Body), forge->Vector }, | |||
{ child_size, child_type } | |||
}; | |||
return lv2_atom_forge_push( | |||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |||
} | |||
/** Write a complete atom:Vector. */ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_vector(LV2_Atom_Forge* forge, | |||
uint32_t child_size, | |||
uint32_t child_type, | |||
uint32_t n_elems, | |||
const void* elems) | |||
{ | |||
const LV2_Atom_Vector a = { | |||
{ (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size), | |||
forge->Vector }, | |||
{ child_size, child_type } | |||
}; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); | |||
if (out) { | |||
lv2_atom_forge_write(forge, elems, child_size * n_elems); | |||
} | |||
return out; | |||
} | |||
/** | |||
Write the header of an atom:Tuple. | |||
The passed frame will be initialised to represent this tuple. To complete | |||
the tuple, write a sequence of atoms, then pop the frame with | |||
lv2_atom_forge_pop(). | |||
For example: | |||
@code | |||
// Write tuple (1, 2.0) | |||
LV2_Atom_Forge_Frame frame; | |||
LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame); | |||
lv2_atom_forge_int32(forge, 1); | |||
lv2_atom_forge_float(forge, 2.0); | |||
lv2_atom_forge_pop(forge, &frame); | |||
@endcode | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) | |||
{ | |||
const LV2_Atom_Tuple a = { { 0, forge->Tuple } }; | |||
return lv2_atom_forge_push( | |||
forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); | |||
} | |||
/** | |||
Write the header of an atom:Resource. | |||
The passed frame will be initialised to represent this object. To complete | |||
the object, write a sequence of properties, then pop the frame with | |||
lv2_atom_forge_pop(). | |||
For example: | |||
@code | |||
LV2_URID eg_Cat = map("http://example.org/Cat"); | |||
LV2_URID eg_name = map("http://example.org/name"); | |||
// Write object header | |||
LV2_Atom_Forge_Frame frame; | |||
lv2_atom_forge_resource(forge, &frame, 1, eg_Cat); | |||
// Write property: eg:name = "Hobbes" | |||
lv2_atom_forge_property_head(forge, eg_name, 0); | |||
lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes")); | |||
// Finish object | |||
lv2_atom_forge_pop(forge, &frame); | |||
@endcode | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_resource(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Frame* frame, | |||
LV2_URID id, | |||
LV2_URID otype) | |||
{ | |||
const LV2_Atom_Object a = { | |||
{ sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Resource }, | |||
{ id, otype } | |||
}; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); | |||
return lv2_atom_forge_push(forge, frame, out); | |||
} | |||
/** | |||
The same as lv2_atom_forge_resource(), but for object:Blank. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_blank(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Frame* frame, | |||
uint32_t id, | |||
LV2_URID otype) | |||
{ | |||
const LV2_Atom_Object a = { | |||
{ sizeof(LV2_Atom_Object) - sizeof(LV2_Atom), forge->Blank }, | |||
{ id, otype } | |||
}; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); | |||
return lv2_atom_forge_push(forge, frame, out); | |||
} | |||
/** | |||
Write the header for a property body (likely in an Object). | |||
See lv2_atom_forge_resource() documentation for an example. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_property_head(LV2_Atom_Forge* forge, | |||
LV2_URID key, | |||
LV2_URID context) | |||
{ | |||
const LV2_Atom_Property_Body a = { key, context, { 0, 0 } }; | |||
return lv2_atom_forge_write(forge, &a, 2 * sizeof(uint32_t)); | |||
} | |||
/** | |||
Write the header for a Sequence. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, | |||
LV2_Atom_Forge_Frame* frame, | |||
uint32_t unit) | |||
{ | |||
const LV2_Atom_Sequence a = { | |||
{ sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom), forge->Sequence }, | |||
{ unit, 0 } | |||
}; | |||
LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); | |||
return lv2_atom_forge_push(forge, frame, out); | |||
} | |||
/** | |||
Write the time stamp header of an Event (in a Sequence) in audio frames. | |||
After this, call the appropriate forge method(s) to write the body. Note | |||
the returned reference is to an LV2_Event which is NOT an Atom. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) | |||
{ | |||
return lv2_atom_forge_write(forge, &frames, sizeof(frames)); | |||
} | |||
/** | |||
Write the time stamp header of an Event (in a Sequence) in beats. After | |||
this, call the appropriate forge method(s) to write the body. Note the | |||
returned reference is to an LV2_Event which is NOT an Atom. | |||
*/ | |||
static inline LV2_Atom_Forge_Ref | |||
lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats) | |||
{ | |||
return lv2_atom_forge_write(forge, &beats, sizeof(beats)); | |||
} | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_ATOM_FORGE_H */ |
@@ -0,0 +1,255 @@ | |||
// lv2_atom_helpers.h | |||
// | |||
/**************************************************************************** | |||
Copyright (C) 2005-2012, rncbc aka Rui Nuno Capela. All rights reserved. | |||
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 (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, write to the Free Software Foundation, Inc., | |||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |||
*****************************************************************************/ | |||
/* Helper functions for LV2 atom:Sequence event buffer. | |||
* | |||
* tentatively adapted from: | |||
* | |||
* - lv2_evbuf.h,c - An abstract/opaque LV2 event buffer implementation. | |||
* | |||
* - event-helpers.h - Helper functions for the LV2 Event extension. | |||
* <http://lv2plug.in/ns/ext/event> | |||
* | |||
* Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
*/ | |||
#ifndef LV2_ATOM_HELPERS_H | |||
#define LV2_ATOM_HELPERS_H | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include <assert.h> | |||
#include "atom.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
// An abstract/opaque LV2 atom:Sequence buffer. | |||
// | |||
typedef | |||
struct _LV2_Atom_Buffer | |||
{ | |||
uint32_t capacity; | |||
uint32_t chunk_type; | |||
uint32_t sequence_type; | |||
LV2_Atom_Sequence atoms; | |||
} LV2_Atom_Buffer; | |||
// Pad a size to 64 bits (for LV2 atom:Sequence event sizes). | |||
// | |||
static inline | |||
uint32_t lv2_atom_buffer_pad_size ( uint32_t size ) | |||
{ | |||
return (size + 7) & (~7); | |||
} | |||
// Clear and initialize an existing LV2 atom:Sequenece buffer. | |||
// | |||
static inline | |||
void lv2_atom_buffer_reset ( LV2_Atom_Buffer *buf, bool input ) | |||
{ | |||
if (input) | |||
buf->atoms.atom.size = sizeof(LV2_Atom_Sequence_Body); | |||
else | |||
buf->atoms.atom.size = buf->capacity; | |||
buf->atoms.atom.type = buf->sequence_type; | |||
buf->atoms.body.unit = 0; | |||
buf->atoms.body.pad = 0; | |||
} | |||
// Allocate a new, empty LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
LV2_Atom_Buffer *lv2_atom_buffer_new ( | |||
uint32_t capacity, uint32_t sequence_type, bool input ) | |||
{ | |||
LV2_Atom_Buffer *buf = (LV2_Atom_Buffer *) | |||
malloc(sizeof(LV2_Atom_Buffer) + sizeof(LV2_Atom_Sequence) + capacity); | |||
buf->capacity = capacity; | |||
buf->sequence_type = sequence_type; | |||
lv2_atom_buffer_reset(buf, input); | |||
return buf; | |||
} | |||
// Free an LV2 atom:Sequenece buffer allocated with lv2_atome_buffer_new. | |||
// | |||
static inline | |||
void lv2_atom_buffer_free ( LV2_Atom_Buffer *buf ) | |||
{ | |||
free(buf); | |||
} | |||
// Return the total padded size of events stored in a LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
uint32_t lv2_atom_buffer_get_size ( LV2_Atom_Buffer *buf ) | |||
{ | |||
return buf->atoms.atom.size - sizeof(LV2_Atom_Sequence_Body); | |||
} | |||
// Return the actual LV2 atom:Sequence implementation. | |||
// | |||
static inline | |||
LV2_Atom_Sequence *lv2_atom_buffer_get_sequence ( LV2_Atom_Buffer *buf ) | |||
{ | |||
return &buf->atoms; | |||
} | |||
// An iterator over an atom:Sequence buffer. | |||
// | |||
typedef | |||
struct _LV2_Atom_Buffer_Iterator | |||
{ | |||
LV2_Atom_Buffer *buf; | |||
uint32_t offset; | |||
} LV2_Atom_Buffer_Iterator; | |||
// Reset an iterator to point to the start of an LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_begin ( | |||
LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf ) | |||
{ | |||
iter->buf = buf; | |||
iter->offset = 0; | |||
return (buf->atoms.atom.size > 0); | |||
} | |||
// Reset an iterator to point to the end of an LV2 atom:Sequence buffer. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_end ( | |||
LV2_Atom_Buffer_Iterator *iter, LV2_Atom_Buffer *buf ) | |||
{ | |||
iter->buf = buf; | |||
iter->offset = lv2_atom_buffer_pad_size(lv2_atom_buffer_get_size(buf)); | |||
return (iter->offset < buf->capacity - sizeof(LV2_Atom_Event)); | |||
} | |||
// Check if a LV2 atom:Sequenece buffer iterator is valid. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_is_valid ( LV2_Atom_Buffer_Iterator *iter ) | |||
{ | |||
return iter->offset < lv2_atom_buffer_get_size(iter->buf); | |||
} | |||
// Advance a LV2 atom:Sequenece buffer iterator forward one event. | |||
// | |||
static inline | |||
bool lv2_atom_buffer_increment ( LV2_Atom_Buffer_Iterator *iter ) | |||
{ | |||
if (!lv2_atom_buffer_is_valid(iter)) | |||
return false; | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
uint32_t size = ((LV2_Atom_Event *) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset))->body.size; | |||
iter->offset += lv2_atom_buffer_pad_size(sizeof(LV2_Atom_Event) + size); | |||
return true; | |||
} | |||
// Get the event currently pointed at a LV2 atom:Sequence buffer iterator. | |||
// | |||
static inline | |||
LV2_Atom_Event *lv2_atom_buffer_get ( | |||
LV2_Atom_Buffer_Iterator *iter, uint8_t **data ) | |||
{ | |||
if (!lv2_atom_buffer_is_valid(iter)) | |||
return NULL; | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
LV2_Atom_Event *ev = (LV2_Atom_Event *) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset); | |||
*data = (uint8_t *) LV2_ATOM_BODY(&ev->body); | |||
return ev; | |||
} | |||
// Write an event at a LV2 atom:Sequence buffer iterator. | |||
static inline | |||
bool lv2_atom_buffer_write ( | |||
LV2_Atom_Buffer_Iterator *iter, | |||
uint32_t frames, | |||
uint32_t /*subframes*/, | |||
uint32_t type, | |||
uint32_t size, | |||
const uint8_t *data ) | |||
{ | |||
LV2_Atom_Buffer *buf = iter->buf; | |||
LV2_Atom_Sequence *atoms = &buf->atoms; | |||
if (buf->capacity - sizeof(LV2_Atom) - atoms->atom.size | |||
< sizeof(LV2_Atom_Event) + size) | |||
return false; | |||
LV2_Atom_Event *ev = (LV2_Atom_Event*) ((char *) | |||
LV2_ATOM_CONTENTS(LV2_Atom_Sequence, atoms) + iter->offset); | |||
ev->time.frames = frames; | |||
ev->body.type = type; | |||
ev->body.size = size; | |||
memcpy(LV2_ATOM_BODY(&ev->body), data, size); | |||
size = lv2_atom_buffer_pad_size(sizeof(LV2_Atom_Event) + size); | |||
atoms->atom.size += size; | |||
iter->offset += size; | |||
return true; | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif // LV2_ATOM_HELPERS_H | |||
// end of lv2_atom_helpers.h |
@@ -0,0 +1,401 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file util.h Helper functions for the LV2 Atom extension. | |||
Note these functions are all static inline, do not take their address. | |||
This header is non-normative, it is provided for convenience. | |||
*/ | |||
#ifndef LV2_ATOM_UTIL_H | |||
#define LV2_ATOM_UTIL_H | |||
#include <stdarg.h> | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include "atom.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** Pad a size to 64 bits. */ | |||
static inline uint32_t | |||
lv2_atom_pad_size(uint32_t size) | |||
{ | |||
return (size + 7) & (~7); | |||
} | |||
/** Return the total size of @p atom, including the header. */ | |||
static inline uint32_t | |||
lv2_atom_total_size(const LV2_Atom* atom) | |||
{ | |||
return sizeof(LV2_Atom) + atom->size; | |||
} | |||
/** Return true iff @p atom is null. */ | |||
static inline bool | |||
lv2_atom_is_null(const LV2_Atom* atom) | |||
{ | |||
return !atom || (atom->type == 0 && atom->size == 0); | |||
} | |||
/** Return true iff @p a is equal to @p b. */ | |||
static inline bool | |||
lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) | |||
{ | |||
return (a == b) || ((a->type == b->type) && | |||
(a->size == b->size) && | |||
!memcmp(a + 1, b + 1, a->size)); | |||
} | |||
/** | |||
@name Sequence Iterator | |||
@{ | |||
*/ | |||
/** Get an iterator pointing to the first event in a Sequence body. */ | |||
static inline const LV2_Atom_Event* | |||
lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) | |||
{ | |||
return (const LV2_Atom_Event*)(body + 1); | |||
} | |||
/** Get an iterator pointing to the end of a Sequence body. */ | |||
static inline const LV2_Atom_Event* | |||
lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size) | |||
{ | |||
return (const LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size)); | |||
} | |||
/** Return true iff @p i has reached the end of @p body. */ | |||
static inline bool | |||
lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, | |||
uint32_t size, | |||
const LV2_Atom_Event* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the element following @p i. */ | |||
static inline const LV2_Atom_Event* | |||
lv2_atom_sequence_next(const LV2_Atom_Event* i) | |||
{ | |||
if (!i) return NULL; | |||
return (const LV2_Atom_Event*)((const uint8_t*)i | |||
+ sizeof(LV2_Atom_Event) | |||
+ lv2_atom_pad_size(i->body.size)); | |||
} | |||
/** | |||
A macro for iterating over all events in a Sequence. | |||
@param seq The sequence to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) { | |||
// Do something with ev (an LV2_Atom_Event*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ | |||
for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(&(seq)->body); \ | |||
!lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ | |||
(iter) = lv2_atom_sequence_next(iter)) | |||
/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ | |||
#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ | |||
for (const LV2_Atom_Event* (iter) = lv2_atom_sequence_begin(body); \ | |||
!lv2_atom_sequence_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_sequence_next(iter)) | |||
/** | |||
@} | |||
@name Tuple Iterator | |||
@{ | |||
*/ | |||
/** Get an iterator pointing to the first element in @p tup. */ | |||
static inline const LV2_Atom* | |||
lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup) | |||
{ | |||
return (const LV2_Atom*)(LV2_ATOM_BODY_CONST(tup)); | |||
} | |||
/** Return true iff @p i has reached the end of @p body. */ | |||
static inline bool | |||
lv2_atom_tuple_is_end(const void* body, uint32_t size, LV2_Atom* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the element following @p i. */ | |||
static inline const LV2_Atom* | |||
lv2_atom_tuple_next(const LV2_Atom* i) | |||
{ | |||
return (const LV2_Atom*)( | |||
(const uint8_t*)i + sizeof(LV2_Atom) + lv2_atom_pad_size(i->size)); | |||
} | |||
/** | |||
A macro for iterating over all properties of a Tuple. | |||
@param tuple The tuple to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOMO_TUPLE_FOREACH(tuple, elem) { | |||
// Do something with elem (an LV2_Atom*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ | |||
for (LV2_Atom* (iter) = lv2_atom_tuple_begin(tuple); \ | |||
!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), (tuple)->size, (iter)); \ | |||
(iter) = lv2_atom_tuple_next(iter)) | |||
/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ | |||
#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ | |||
for (LV2_Atom* (iter) = (LV2_Atom*)body; \ | |||
!lv2_atom_tuple_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_tuple_next(iter)) | |||
/** | |||
@} | |||
@name Object Iterator | |||
@{ | |||
*/ | |||
/** Return a pointer to the first property in @p body. */ | |||
static inline const LV2_Atom_Property_Body* | |||
lv2_atom_object_begin(const LV2_Atom_Object_Body* body) | |||
{ | |||
return (const LV2_Atom_Property_Body*)(body + 1); | |||
} | |||
/** Return true iff @p i has reached the end of @p obj. */ | |||
static inline bool | |||
lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, | |||
uint32_t size, | |||
const LV2_Atom_Property_Body* i) | |||
{ | |||
return (const uint8_t*)i >= ((const uint8_t*)body + size); | |||
} | |||
/** Return an iterator to the property following @p i. */ | |||
static inline const LV2_Atom_Property_Body* | |||
lv2_atom_object_next(const LV2_Atom_Property_Body* i) | |||
{ | |||
const LV2_Atom* const value = (const LV2_Atom*)( | |||
(const uint8_t*)i + 2 * sizeof(uint32_t)); | |||
return (const LV2_Atom_Property_Body*)( | |||
(const uint8_t*)i + lv2_atom_pad_size(sizeof(LV2_Atom_Property_Body) | |||
+ value->size)); | |||
} | |||
/** | |||
A macro for iterating over all properties of an Object. | |||
@param obj The object to iterate over | |||
@param iter The name of the iterator | |||
This macro is used similarly to a for loop (which it expands to), e.g.: | |||
@code | |||
LV2_ATOM_OBJECT_FOREACH(object, i) { | |||
// Do something with prop (an LV2_Atom_Property_Body*) here... | |||
} | |||
@endcode | |||
*/ | |||
#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ | |||
for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(&(obj)->body); \ | |||
!lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ | |||
(iter) = lv2_atom_object_next(iter)) | |||
/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ | |||
#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ | |||
for (const LV2_Atom_Property_Body* (iter) = lv2_atom_object_begin(body); \ | |||
!lv2_atom_object_is_end(body, size, (iter)); \ | |||
(iter) = lv2_atom_object_next(iter)) | |||
/** | |||
@} | |||
@name Object Query | |||
@{ | |||
*/ | |||
/** A single entry in an Object query. */ | |||
typedef struct { | |||
uint32_t key; /**< Key to query (input set by user) */ | |||
const LV2_Atom** value; /**< Found value (output set by query function) */ | |||
} LV2_Atom_Object_Query; | |||
static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = { 0, NULL }; | |||
/** | |||
Get an object's values for various keys. | |||
The value pointer of each item in @p query will be set to the location of | |||
the corresponding value in @p object. Every value pointer in @p query MUST | |||
be initialised to NULL. This function reads @p object in a single linear | |||
sweep. By allocating @p query on the stack, objects can be "queried" | |||
quickly without allocating any memory. This function is realtime safe. | |||
This function can only do "flat" queries, it is not smart enough to match | |||
variables in nested objects. | |||
For example: | |||
@code | |||
const LV2_Atom* name = NULL; | |||
const LV2_Atom* age = NULL; | |||
LV2_Atom_Object_Query q[] = { | |||
{ urids.eg_name, &name }, | |||
{ urids.eg_age, &age }, | |||
LV2_ATOM_OBJECT_QUERY_END | |||
}; | |||
lv2_atom_object_query(obj, q); | |||
// name and age are now set to the appropriate values in obj, or NULL. | |||
@endcode | |||
*/ | |||
static inline int | |||
lv2_atom_object_query(const LV2_Atom_Object* object, | |||
LV2_Atom_Object_Query* query) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of query keys so we can short-circuit when done */ | |||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) { | |||
++n_queries; | |||
} | |||
LV2_ATOM_OBJECT_FOREACH(object, prop) { | |||
for (LV2_Atom_Object_Query* q = query; q->key; ++q) { | |||
if (q->key == prop->key && !*q->value) { | |||
*q->value = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
} | |||
return matches; | |||
} | |||
/** | |||
Body only version of lv2_atom_object_get(). | |||
*/ | |||
static inline int | |||
lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of keys so we can short-circuit when done */ | |||
va_list args; | |||
va_start(args, body); | |||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { | |||
if (!va_arg(args, const LV2_Atom**)) { | |||
return -1; | |||
} | |||
} | |||
va_end(args); | |||
LV2_ATOM_OBJECT_BODY_FOREACH(body, size, prop) { | |||
va_start(args, body); | |||
for (int i = 0; i < n_queries; ++i) { | |||
uint32_t qkey = va_arg(args, uint32_t); | |||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**); | |||
if (qkey == prop->key && !*qval) { | |||
*qval = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
va_end(args); | |||
} | |||
return matches; | |||
} | |||
/** | |||
Variable argument version of lv2_atom_object_query(). | |||
This is nicer-looking in code, but a bit more error-prone since it is not | |||
type safe and the argument list must be terminated. | |||
The arguments should be a series of uint32_t key and const LV2_Atom** value | |||
pairs, terminated by a zero key. The value pointers MUST be initialized to | |||
NULL. For example: | |||
@code | |||
const LV2_Atom* name = NULL; | |||
const LV2_Atom* age = NULL; | |||
lv2_atom_object_get(obj, | |||
uris.name_key, &name, | |||
uris.age_key, &age, | |||
0); | |||
@endcode | |||
*/ | |||
static inline int | |||
lv2_atom_object_get(const LV2_Atom_Object* object, ...) | |||
{ | |||
int matches = 0; | |||
int n_queries = 0; | |||
/* Count number of keys so we can short-circuit when done */ | |||
va_list args; | |||
va_start(args, object); | |||
for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { | |||
if (!va_arg(args, const LV2_Atom**)) { | |||
return -1; | |||
} | |||
} | |||
va_end(args); | |||
LV2_ATOM_OBJECT_FOREACH(object, prop) { | |||
va_start(args, object); | |||
for (int i = 0; i < n_queries; ++i) { | |||
uint32_t qkey = va_arg(args, uint32_t); | |||
const LV2_Atom** qval = va_arg(args, const LV2_Atom**); | |||
if (qkey == prop->key && !*qval) { | |||
*qval = &prop->value; | |||
if (++matches == n_queries) { | |||
return matches; | |||
} | |||
break; | |||
} | |||
} | |||
va_end(args); | |||
} | |||
return matches; | |||
} | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_ATOM_UTIL_H */ |
@@ -0,0 +1,246 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file atom.h C header for the LV2 Atom extension | |||
<http://lv2plug.in/ns/ext/atom>. | |||
*/ | |||
#ifndef LV2_ATOM_H | |||
#define LV2_ATOM_H | |||
#include <stdint.h> | |||
#include <stddef.h> | |||
#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" | |||
#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" | |||
#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" | |||
#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" | |||
#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" | |||
#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" | |||
#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" | |||
#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" | |||
#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" | |||
#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" | |||
#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" | |||
#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" | |||
#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" | |||
#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" | |||
#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" | |||
#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" | |||
#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" | |||
#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" | |||
#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" | |||
#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" | |||
#define LV2_ATOM__String LV2_ATOM_PREFIX "String" | |||
#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" | |||
#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" | |||
#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" | |||
#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" | |||
#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" | |||
#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" | |||
#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" | |||
#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" | |||
#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" | |||
#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" | |||
#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" | |||
#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" | |||
#define LV2_ATOM_REFERENCE_TYPE 0 | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** This expression will fail to compile if double does not fit in 64 bits. */ | |||
typedef char lv2_atom_assert_double_fits_in_64_bits[ | |||
((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; | |||
/** | |||
Return a pointer to the contents of an Atom. The "contents" of an atom | |||
is the data past the complete type-specific header. | |||
@param type The type of the atom, e.g. LV2_Atom_String. | |||
@param atom A variable-sized atom. | |||
*/ | |||
#define LV2_ATOM_CONTENTS(type, atom) \ | |||
((uint8_t*)(atom) + sizeof(type)) | |||
/** | |||
Const version of LV2_ATOM_CONTENTS. | |||
*/ | |||
#define LV2_ATOM_CONTENTS_CONST(type, atom) \ | |||
((const uint8_t*)(atom) + sizeof(type)) | |||
/** | |||
Return a pointer to the body of an Atom. The "body" of an atom is the | |||
data just past the LV2_Atom head (i.e. the same offset for all types). | |||
*/ | |||
#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom) | |||
/** | |||
Const version of LV2_ATOM_BODY. | |||
*/ | |||
#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom) | |||
/** The header of an atom:Atom. */ | |||
typedef struct { | |||
uint32_t size; /**< Size in bytes, not including type and size. */ | |||
uint32_t type; /**< Type of this atom (mapped URI). */ | |||
} LV2_Atom; | |||
/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
int32_t body; /**< Integer value. */ | |||
} LV2_Atom_Int; | |||
/** An atom:Long. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
int64_t body; /**< Integer value. */ | |||
} LV2_Atom_Long; | |||
/** An atom:Float. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
float body; /**< Floating point value. */ | |||
} LV2_Atom_Float; | |||
/** An atom:Double. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
double body; /**< Floating point value. */ | |||
} LV2_Atom_Double; | |||
/** An atom:Bool. May be cast to LV2_Atom. */ | |||
typedef LV2_Atom_Int LV2_Atom_Bool; | |||
/** An atom:URID. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
uint32_t body; /**< URID. */ | |||
} LV2_Atom_URID; | |||
/** An atom:String. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
/* Contents (a null-terminated UTF-8 string) follow here. */ | |||
} LV2_Atom_String; | |||
/** The body of an atom:Literal. */ | |||
typedef struct { | |||
uint32_t datatype; /**< Datatype URID. */ | |||
uint32_t lang; /**< Language URID. */ | |||
/* Contents (a null-terminated UTF-8 string) follow here. */ | |||
} LV2_Atom_Literal_Body; | |||
/** An atom:Literal. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Literal_Body body; /**< Body. */ | |||
} LV2_Atom_Literal; | |||
/** An atom:Tuple. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
/* Contents (a series of complete atoms) follow here. */ | |||
} LV2_Atom_Tuple; | |||
/** The body of an atom:Vector. */ | |||
typedef struct { | |||
uint32_t child_size; /**< The size of each element in the vector. */ | |||
uint32_t child_type; /**< The type of each element in the vector. */ | |||
/* Contents (a series of packed atom bodies) follow here. */ | |||
} LV2_Atom_Vector_Body; | |||
/** An atom:Vector. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Vector_Body body; /**< Body. */ | |||
} LV2_Atom_Vector; | |||
/** The body of an atom:Property (e.g. in an atom:Object). */ | |||
typedef struct { | |||
uint32_t key; /**< Key (predicate) (mapped URI). */ | |||
uint32_t context; /**< Context URID (may be, and generally is, 0). */ | |||
LV2_Atom value; /**< Value atom header. */ | |||
/* Value atom body follows here. */ | |||
} LV2_Atom_Property_Body; | |||
/** An atom:Property. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Property_Body body; /**< Body. */ | |||
} LV2_Atom_Property; | |||
/** The body of an atom:Object. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
uint32_t id; /**< URID (atom:Resource) or blank ID (atom:Blank). */ | |||
uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ | |||
/* Contents (a series of property bodies) follow here. */ | |||
} LV2_Atom_Object_Body; | |||
/** An atom:Object. May be cast to LV2_Atom. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Object_Body body; /**< Body. */ | |||
} LV2_Atom_Object; | |||
/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */ | |||
typedef struct { | |||
/** Time stamp. Which type is valid is determined by context. */ | |||
union { | |||
int64_t frames; /**< Time in audio frames. */ | |||
double beats; /**< Time in beats. */ | |||
} time; | |||
LV2_Atom body; /**< Event body atom header. */ | |||
/* Body atom contents follow here. */ | |||
} LV2_Atom_Event; | |||
/** | |||
The body of an atom:Sequence (a sequence of events). | |||
The unit field is either a URID that described an appropriate time stamp | |||
type, or may be 0 where a default stamp type is known. For | |||
LV2_Descriptor::run(), the default stamp type is audio frames. | |||
The contents of a sequence is a series of LV2_Atom_Event, each aligned | |||
to 64-bits, e.g.: | |||
<pre> | |||
| Event 1 (size 6) | Event 2 | |||
| | | | | | | | | | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |||
|FRAMES |SUBFRMS|TYPE |SIZE |DATADATADATAPAD|FRAMES |SUBFRMS|... | |||
</pre> | |||
*/ | |||
typedef struct { | |||
uint32_t unit; /**< URID of unit of event time stamps. */ | |||
uint32_t pad; /**< Currently unused. */ | |||
/* Contents (a series of events) follow here. */ | |||
} LV2_Atom_Sequence_Body; | |||
/** An atom:Sequence. */ | |||
typedef struct { | |||
LV2_Atom atom; /**< Atom header. */ | |||
LV2_Atom_Sequence_Body body; /**< Body. */ | |||
} LV2_Atom_Sequence; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_ATOM_H */ |
@@ -0,0 +1,30 @@ | |||
/* | |||
Copyright 2007-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_BUF_SIZE_H | |||
#define LV2_BUF_SIZE_H | |||
#define LV2_BUF_SIZE_URI "http://lv2plug.in/ns/ext/buf-size" | |||
#define LV2_BUF_SIZE_PREFIX LV2_BUF_SIZE_URI "#" | |||
#define LV2_BUF_SIZE__boundedBlockLength LV2_BUF_SIZE_PREFIX "boundedBlockLength" | |||
#define LV2_BUF_SIZE__fixedBlockLength LV2_BUF_SIZE_PREFIX "fixedBlockLength" | |||
#define LV2_BUF_SIZE__maxBlockLength LV2_BUF_SIZE_PREFIX "maxBlockLength" | |||
#define LV2_BUF_SIZE__minBlockLength LV2_BUF_SIZE_PREFIX "minBlockLength" | |||
#define LV2_BUF_SIZE__powerOf2BlockLength LV2_BUF_SIZE_PREFIX "powerOf2BlockLength" | |||
#define LV2_BUF_SIZE__sequenceSize LV2_BUF_SIZE_PREFIX "sequenceSize" | |||
#endif /* LV2_BUF_SIZE_H */ |
@@ -0,0 +1,63 @@ | |||
/* | |||
LV2 Data Access Extension | |||
Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file data-access.h | |||
C header for the LV2 Extension Data extension | |||
<http://lv2plug.in/ns/ext/data-access>. | |||
This extension defines a method for (e.g.) plugin UIs to have (possibly | |||
marshalled) access to the extension_data function on a plugin instance. | |||
*/ | |||
#ifndef LV2_DATA_ACCESS_H | |||
#define LV2_DATA_ACCESS_H | |||
#define LV2_DATA_ACCESS_URI "http://lv2plug.in/ns/ext/data-access" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
The data field of the LV2_Feature for this extension. | |||
To support this feature the host must pass an LV2_Feature struct to the | |||
instantiate method with URI "http://lv2plug.in/ns/ext/data-access" | |||
and data pointed to an instance of this struct. | |||
*/ | |||
typedef struct { | |||
/** | |||
A pointer to a method the UI can call to get data (of a type specified | |||
by some other extension) from the plugin. | |||
This call never is never guaranteed to return anything, UIs should | |||
degrade gracefully if direct access to the plugin data is not possible | |||
(in which case this function will return NULL). | |||
This is for access to large data that can only possibly work if the UI | |||
and plugin are running in the same process. For all other things, use | |||
the normal LV2 UI communication system. | |||
*/ | |||
const void* (*data_access)(const char* uri); | |||
} LV2_Extension_Data_Feature; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_DATA_ACCESS_H */ |
@@ -0,0 +1,144 @@ | |||
/* | |||
Dynamic manifest specification for LV2 | |||
Copyright 2008-2011 Stefano D'Angelo <zanga.mail@gmail.com> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file dynmanifest.h | |||
C header for the LV2 Dynamic Manifest extension | |||
<http://lv2plug.in/ns/ext/dynmanifest>. | |||
Revision: 1.2 | |||
*/ | |||
#ifndef LV2_DYN_MANIFEST_H_INCLUDED | |||
#define LV2_DYN_MANIFEST_H_INCLUDED | |||
#include <stdio.h> | |||
#include "lv2.h" | |||
#define LV2_DYN_MANIFEST_URI "http://lv2plug.in/ns/ext/dynmanifest" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
Dynamic manifest generator handle. | |||
This handle indicates a particular status of a dynamic manifest generator. | |||
The host MUST NOT attempt to interpret it and, unlikely LV2_Handle, it is | |||
NOT even valid to compare this to NULL. The dynamic manifest generator MAY | |||
use it to reference internal data. | |||
*/ | |||
typedef void * LV2_Dyn_Manifest_Handle; | |||
/** | |||
Generate the dynamic manifest. | |||
@param handle Pointer to an uninitialized dynamic manifest generator handle. | |||
@param features NULL terminated array of LV2_Feature structs which represent | |||
the features the host supports. The dynamic manifest generator may refuse to | |||
(re)generate the dynamic manifest if required features are not found here | |||
(however hosts SHOULD NOT use this as a discovery mechanism, instead of | |||
reading the static manifest file). This array must always exist; if a host | |||
has no features, it MUST pass a single element array containing NULL. | |||
@return 0 on success, otherwise a non-zero error code. The host SHOULD | |||
evaluate the result of the operation by examining the returned value and | |||
MUST NOT try to interpret the value of handle. | |||
*/ | |||
int lv2_dyn_manifest_open(LV2_Dyn_Manifest_Handle * handle, | |||
const LV2_Feature *const * features); | |||
/** | |||
Fetch a "list" of subject URIs described in the dynamic manifest. | |||
The dynamic manifest generator has to fill the resource only with the needed | |||
triples to make the host aware of the "objects" it wants to expose. For | |||
example, if the plugin library exposes a regular LV2 plugin, it should | |||
output only a triple like the following: | |||
<http://www.example.com/plugin/uri> a lv2:Plugin . | |||
The objects that are elegible for exposure are those that would need to be | |||
represented by a subject node in a static manifest. | |||
@param handle Dynamic manifest generator handle. | |||
@param fp FILE * identifying the resource the host has to set up for the | |||
dynamic manifest generator. The host MUST pass a writable, empty resource to | |||
this function, and the dynamic manifest generator MUST ONLY perform write | |||
operations on it at the end of the stream (e.g., using only fprintf(), | |||
fwrite() and similar). | |||
@return 0 on success, otherwise a non-zero error code. | |||
*/ | |||
int lv2_dyn_manifest_get_subjects(LV2_Dyn_Manifest_Handle handle, | |||
FILE * fp); | |||
/** | |||
Function that fetches data related to a specific URI. | |||
The dynamic manifest generator has to fill the resource with data related to | |||
object represented by the given URI. For example, if the library exposes a | |||
regular LV2 plugin whose URI, as retrieved by the host using | |||
lv2_dyn_manifest_get_subjects() is http://www.example.com/plugin/uri, it | |||
should output something like: | |||
<pre> | |||
<http://www.example.com/plugin/uri> | |||
a lv2:Plugin ; | |||
doap:name "My Plugin" ; | |||
lv2:binary <mylib.so> ; | |||
etc:etc "..." . | |||
</pre> | |||
@param handle Dynamic manifest generator handle. | |||
@param fp FILE * identifying the resource the host has to set up for the | |||
dynamic manifest generator. The host MUST pass a writable resource to this | |||
function, and the dynamic manifest generator MUST ONLY perform write | |||
operations on it at the current position of the stream (e.g. using only | |||
fprintf(), fwrite() and similar). | |||
@param uri URI to get data about (in the "plain" form, i.e., absolute URI | |||
without Turtle prefixes). | |||
@return 0 on success, otherwise a non-zero error code. | |||
*/ | |||
int lv2_dyn_manifest_get_data(LV2_Dyn_Manifest_Handle handle, | |||
FILE * fp, | |||
const char * uri); | |||
/** | |||
Function that ends the operations on the dynamic manifest generator. | |||
This function SHOULD be used by the dynamic manifest generator to perform | |||
cleanup operations, etc. | |||
Once this function is called, referring to handle will cause undefined | |||
behavior. | |||
@param handle Dynamic manifest generator handle. | |||
*/ | |||
void lv2_dyn_manifest_close(LV2_Dyn_Manifest_Handle handle); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* LV2_DYN_MANIFEST_H_INCLUDED */ |
@@ -0,0 +1,263 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file event-helpers.h Helper functions for the LV2 Event extension | |||
<http://lv2plug.in/ns/ext/event>. | |||
*/ | |||
#ifndef LV2_EVENT_HELPERS_H | |||
#define LV2_EVENT_HELPERS_H | |||
#include <stdint.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include "event.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** @file | |||
* Helper functions for the LV2 Event extension | |||
* <http://lv2plug.in/ns/ext/event>. | |||
* | |||
* These functions are provided for convenience only, use of them is not | |||
* required for supporting lv2ev (i.e. the events extension is defined by the | |||
* raw buffer format described in lv2_event.h and NOT by this API). | |||
* | |||
* Note that these functions are all static inline which basically means: | |||
* do not take the address of these functions. */ | |||
/** Pad a size to 64 bits (for event sizes) */ | |||
static inline uint16_t | |||
lv2_event_pad_size(uint16_t size) | |||
{ | |||
return (size + 7) & (~7); | |||
} | |||
/** Initialize (empty, reset..) an existing event buffer. | |||
* The contents of buf are ignored entirely and overwritten, except capacity | |||
* which is unmodified. */ | |||
static inline void | |||
lv2_event_buffer_reset(LV2_Event_Buffer* buf, | |||
uint16_t stamp_type, | |||
uint8_t *data) | |||
{ | |||
buf->data = data; | |||
buf->header_size = sizeof(LV2_Event_Buffer); | |||
buf->stamp_type = stamp_type; | |||
buf->event_count = 0; | |||
buf->size = 0; | |||
} | |||
/** Allocate a new, empty event buffer. */ | |||
static inline LV2_Event_Buffer* | |||
lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type) | |||
{ | |||
const size_t size = sizeof(LV2_Event_Buffer) + capacity; | |||
LV2_Event_Buffer* buf = (LV2_Event_Buffer*)malloc(size); | |||
if (buf != NULL) { | |||
buf->capacity = capacity; | |||
lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1)); | |||
return buf; | |||
} else { | |||
return NULL; | |||
} | |||
} | |||
/** An iterator over an LV2_Event_Buffer. | |||
* | |||
* Multiple simultaneous read iterators over a single buffer is fine, | |||
* but changing the buffer invalidates all iterators (e.g. RW Lock). */ | |||
typedef struct { | |||
LV2_Event_Buffer* buf; | |||
uint32_t offset; | |||
} LV2_Event_Iterator; | |||
/** Reset an iterator to point to the start of @a buf. | |||
* @return True if @a iter is valid, otherwise false (buffer is empty) */ | |||
static inline bool | |||
lv2_event_begin(LV2_Event_Iterator* iter, | |||
LV2_Event_Buffer* buf) | |||
{ | |||
iter->buf = buf; | |||
iter->offset = 0; | |||
return (buf->size > 0); | |||
} | |||
/** Check if @a iter is valid. | |||
* @return True if @a iter is valid, otherwise false (past end of buffer) */ | |||
static inline bool | |||
lv2_event_is_valid(LV2_Event_Iterator* iter) | |||
{ | |||
return (iter->buf && (iter->offset < iter->buf->size)); | |||
} | |||
/** Advance @a iter forward one event. | |||
* @a iter must be valid. | |||
* @return True if @a iter is valid, otherwise false (reached end of buffer) */ | |||
static inline bool | |||
lv2_event_increment(LV2_Event_Iterator* iter) | |||
{ | |||
if (!lv2_event_is_valid(iter)) { | |||
return false; | |||
} | |||
LV2_Event* const ev = (LV2_Event*)( | |||
(uint8_t*)iter->buf->data + iter->offset); | |||
iter->offset += lv2_event_pad_size(sizeof(LV2_Event) + ev->size); | |||
return true; | |||
} | |||
/** Dereference an event iterator (get the event currently pointed at). | |||
* @a iter must be valid. | |||
* @a data if non-NULL, will be set to point to the contents of the event | |||
* returned. | |||
* @return A Pointer to the event @a iter is currently pointing at, or NULL | |||
* if the end of the buffer is reached (in which case @a data is | |||
* also set to NULL). */ | |||
static inline LV2_Event* | |||
lv2_event_get(LV2_Event_Iterator* iter, | |||
uint8_t** data) | |||
{ | |||
if (!lv2_event_is_valid(iter)) { | |||
return NULL; | |||
} | |||
LV2_Event* const ev = (LV2_Event*)( | |||
(uint8_t*)iter->buf->data + iter->offset); | |||
if (data) | |||
*data = (uint8_t*)ev + sizeof(LV2_Event); | |||
return ev; | |||
} | |||
/** Write an event at @a iter. | |||
* The event (if any) pointed to by @a iter will be overwritten, and @a iter | |||
* incremented to point to the following event (i.e. several calls to this | |||
* function can be done in sequence without twiddling iter in-between). | |||
* @return True if event was written, otherwise false (buffer is full). */ | |||
static inline bool | |||
lv2_event_write(LV2_Event_Iterator* iter, | |||
uint32_t frames, | |||
uint32_t subframes, | |||
uint16_t type, | |||
uint16_t size, | |||
const uint8_t* data) | |||
{ | |||
if (!iter->buf) | |||
return false; | |||
if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) | |||
return false; | |||
LV2_Event* const ev = (LV2_Event*)( | |||
(uint8_t*)iter->buf->data + iter->offset); | |||
ev->frames = frames; | |||
ev->subframes = subframes; | |||
ev->type = type; | |||
ev->size = size; | |||
memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size); | |||
++iter->buf->event_count; | |||
size = lv2_event_pad_size(sizeof(LV2_Event) + size); | |||
iter->buf->size += size; | |||
iter->offset += size; | |||
return true; | |||
} | |||
/** Reserve space for an event in the buffer and return a pointer to | |||
the memory where the caller can write the event data, or NULL if there | |||
is not enough room in the buffer. */ | |||
static inline uint8_t* | |||
lv2_event_reserve(LV2_Event_Iterator* iter, | |||
uint32_t frames, | |||
uint32_t subframes, | |||
uint16_t type, | |||
uint16_t size) | |||
{ | |||
if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size) | |||
return NULL; | |||
LV2_Event* const ev = (LV2_Event*)((uint8_t*)iter->buf->data + | |||
iter->offset); | |||
ev->frames = frames; | |||
ev->subframes = subframes; | |||
ev->type = type; | |||
ev->size = size; | |||
++iter->buf->event_count; | |||
size = lv2_event_pad_size(sizeof(LV2_Event) + size); | |||
iter->buf->size += size; | |||
iter->offset += size; | |||
return (uint8_t*)ev + sizeof(LV2_Event); | |||
} | |||
/** Write an event at @a iter. | |||
* The event (if any) pointed to by @a iter will be overwritten, and @a iter | |||
* incremented to point to the following event (i.e. several calls to this | |||
* function can be done in sequence without twiddling iter in-between). | |||
* @return True if event was written, otherwise false (buffer is full). */ | |||
static inline bool | |||
lv2_event_write_event(LV2_Event_Iterator* iter, | |||
const LV2_Event* ev, | |||
const uint8_t* data) | |||
{ | |||
if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + ev->size) | |||
return false; | |||
LV2_Event* const write_ev = (LV2_Event*)( | |||
(uint8_t*)iter->buf->data + iter->offset); | |||
*write_ev = *ev; | |||
memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size); | |||
++iter->buf->event_count; | |||
const uint16_t size = lv2_event_pad_size(sizeof(LV2_Event) + ev->size); | |||
iter->buf->size += size; | |||
iter->offset += size; | |||
return true; | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_EVENT_HELPERS_H */ | |||
@@ -0,0 +1,294 @@ | |||
/* | |||
Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
Copyright 2006-2007 Lars Luthman <lars.luthman@gmail.com> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file event.h | |||
C API for the LV2 Event extension <http://lv2plug.in/ns/ext/event>. | |||
This extension is a generic transport mechanism for time stamped events | |||
of any type (e.g. MIDI, OSC, ramps, etc). Each port can transport mixed | |||
events of any type; the type of events and timestamps are defined by a URI | |||
which is mapped to an integer by the host for performance reasons. | |||
This extension requires the host to support the LV2 URI Map extension. | |||
Any host which supports this extension MUST guarantee that any call to | |||
the LV2 URI Map uri_to_id function with the URI of this extension as the | |||
'map' argument returns a value within the range of uint16_t. | |||
*/ | |||
#ifndef LV2_EVENT_H | |||
#define LV2_EVENT_H | |||
#define LV2_EVENT_URI "http://lv2plug.in/ns/ext/event" | |||
#define LV2_EVENT_PREFIX LV2_EVENT_URI "#" | |||
#define LV2_EVENT__Event LV2_EVENT_PREFIX "Event" | |||
#define LV2_EVENT__EventPort LV2_EVENT_PREFIX "EventPort" | |||
#define LV2_EVENT__FrameStamp LV2_EVENT_PREFIX "FrameStamp" | |||
#define LV2_EVENT__TimeStamp LV2_EVENT_PREFIX "TimeStamp" | |||
#define LV2_EVENT__generatesTimeStamp LV2_EVENT_PREFIX "generatesTimeStamp" | |||
#define LV2_EVENT__generic LV2_EVENT_PREFIX "generic" | |||
#define LV2_EVENT__inheritsEvent LV2_EVENT_PREFIX "inheritsEvent" | |||
#define LV2_EVENT__inheritsTimeStamp LV2_EVENT_PREFIX "inheritsTimeStamp" | |||
#define LV2_EVENT__supportsEvent LV2_EVENT_PREFIX "supportsEvent" | |||
#define LV2_EVENT__supportsTimeStamp LV2_EVENT_PREFIX "supportsTimeStamp" | |||
#define LV2_EVENT_AUDIO_STAMP 0 | |||
#include <stdint.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
The best Pulses Per Quarter Note for tempo-based uint32_t timestamps. | |||
Equal to 2^12 * 5 * 7 * 9 * 11 * 13 * 17, which is evenly divisble | |||
by all integers from 1 through 18 inclusive, and powers of 2 up to 2^12. | |||
*/ | |||
static const uint32_t LV2_EVENT_PPQN = 3136573440U; | |||
/** | |||
An LV2 event (header only). | |||
LV2 events are generic time-stamped containers for any type of event. | |||
The type field defines the format of a given event's contents. | |||
This struct defines the header of an LV2 event. An LV2 event is a single | |||
chunk of POD (plain old data), usually contained in a flat buffer (see | |||
LV2_EventBuffer below). Unless a required feature says otherwise, hosts may | |||
assume a deep copy of an LV2 event can be created safely using a simple: | |||
memcpy(ev_copy, ev, sizeof(LV2_Event) + ev->size); (or equivalent) | |||
*/ | |||
typedef struct { | |||
/** | |||
The frames portion of timestamp. The units used here can optionally be | |||
set for a port (with the lv2ev:timeUnits property), otherwise this is | |||
audio frames, corresponding to the sample_count parameter of the LV2 run | |||
method (e.g. frame 0 is the first frame for that call to run). | |||
*/ | |||
uint32_t frames; | |||
/** | |||
The sub-frames portion of timestamp. The units used here can optionally | |||
be set for a port (with the lv2ev:timeUnits property), otherwise this is | |||
1/(2^32) of an audio frame. | |||
*/ | |||
uint32_t subframes; | |||
/** | |||
The type of this event, as a number which represents some URI | |||
defining an event type. This value MUST be some value previously | |||
returned from a call to the uri_to_id function defined in the LV2 | |||
URI map extension (see lv2_uri_map.h). | |||
There are special rules which must be followed depending on the type | |||
of an event. If the plugin recognizes an event type, the definition | |||
of that event type will describe how to interpret the event, and | |||
any required behaviour. Otherwise, if the type is 0, this event is a | |||
non-POD event and lv2_event_unref MUST be called if the event is | |||
'dropped' (see above). Even if the plugin does not understand an event, | |||
it may pass the event through to an output by simply copying (and NOT | |||
calling lv2_event_unref). These rules are designed to allow for generic | |||
event handling plugins and large non-POD events, but with minimal hassle | |||
on simple plugins that "don't care" about these more advanced features. | |||
*/ | |||
uint16_t type; | |||
/** | |||
The size of the data portion of this event in bytes, which immediately | |||
follows. The header size (12 bytes) is not included in this value. | |||
*/ | |||
uint16_t size; | |||
/* size bytes of data follow here */ | |||
} LV2_Event; | |||
/** | |||
A buffer of LV2 events (header only). | |||
Like events (which this contains) an event buffer is a single chunk of POD: | |||
the entire buffer (including contents) can be copied with a single memcpy. | |||
The first contained event begins sizeof(LV2_EventBuffer) bytes after the | |||
start of this struct. | |||
After this header, the buffer contains an event header (defined by struct | |||
LV2_Event), followed by that event's contents (padded to 64 bits), followed | |||
by another header, etc: | |||
| | | | | | | | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | |||
|FRAMES |SUBFRMS|TYP|LEN|DATA..DATA..PAD|FRAMES | ... | |||
*/ | |||
typedef struct { | |||
/** | |||
The contents of the event buffer. This may or may not reside in the | |||
same block of memory as this header, plugins must not assume either. | |||
The host guarantees this points to at least capacity bytes of allocated | |||
memory (though only size bytes of that are valid events). | |||
*/ | |||
uint8_t* data; | |||
/** | |||
The size of this event header in bytes (including everything). | |||
This is to allow for extending this header in the future without | |||
breaking binary compatibility. Whenever this header is copied, | |||
it MUST be done using this field (and NOT the sizeof this struct). | |||
*/ | |||
uint16_t header_size; | |||
/** | |||
The type of the time stamps for events in this buffer. | |||
As a special exception, '0' always means audio frames and subframes | |||
(1/UINT32_MAX'th of a frame) in the sample rate passed to instantiate. | |||
INPUTS: The host must set this field to the numeric ID of some URI | |||
defining the meaning of the frames/subframes fields of contained events | |||
(obtained by the LV2 URI Map uri_to_id function with the URI of this | |||
extension as the 'map' argument, see lv2_uri_map.h). The host must | |||
never pass a plugin a buffer which uses a stamp type the plugin does not | |||
'understand'. The value of this field must never change, except when | |||
connect_port is called on the input port, at which time the host MUST | |||
have set the stamp_type field to the value that will be used for all | |||
subsequent run calls. | |||
OUTPUTS: The plugin may set this to any value that has been returned | |||
from uri_to_id with the URI of this extension for a 'map' argument. | |||
When connected to a buffer with connect_port, output ports MUST set this | |||
field to the type of time stamp they will be writing. On any call to | |||
connect_port on an event input port, the plugin may change this field on | |||
any output port, it is the responsibility of the host to check if any of | |||
these values have changed and act accordingly. | |||
*/ | |||
uint16_t stamp_type; | |||
/** | |||
The number of events in this buffer. | |||
INPUTS: The host must set this field to the number of events contained | |||
in the data buffer before calling run(). The plugin must not change | |||
this field. | |||
OUTPUTS: The plugin must set this field to the number of events it has | |||
written to the buffer before returning from run(). Any initial value | |||
should be ignored by the plugin. | |||
*/ | |||
uint32_t event_count; | |||
/** | |||
The size of the data buffer in bytes. | |||
This is set by the host and must not be changed by the plugin. | |||
The host is allowed to change this between run() calls. | |||
*/ | |||
uint32_t capacity; | |||
/** | |||
The size of the initial portion of the data buffer containing data. | |||
INPUTS: The host must set this field to the number of bytes used | |||
by all events it has written to the buffer (including headers) | |||
before calling the plugin's run(). | |||
The plugin must not change this field. | |||
OUTPUTS: The plugin must set this field to the number of bytes | |||
used by all events it has written to the buffer (including headers) | |||
before returning from run(). | |||
Any initial value should be ignored by the plugin. | |||
*/ | |||
uint32_t size; | |||
} LV2_Event_Buffer; | |||
/** | |||
Opaque pointer to host data. | |||
*/ | |||
typedef void* LV2_Event_Callback_Data; | |||
/** | |||
Non-POD events feature. | |||
To support this feature the host must pass an LV2_Feature struct to the | |||
plugin's instantiate method with URI "http://lv2plug.in/ns/ext/event" | |||
and data pointed to an instance of this struct. Note this feature | |||
is not mandatory to support the event extension. | |||
*/ | |||
typedef struct { | |||
/** | |||
Opaque pointer to host data. | |||
The plugin MUST pass this to any call to functions in this struct. | |||
Otherwise, it must not be interpreted in any way. | |||
*/ | |||
LV2_Event_Callback_Data callback_data; | |||
/** | |||
Take a reference to a non-POD event. | |||
If a plugin receives an event with type 0, it means the event is a | |||
pointer to some object in memory and not a flat sequence of bytes | |||
in the buffer. When receiving a non-POD event, the plugin already | |||
has an implicit reference to the event. If the event is stored AND | |||
passed to an output, lv2_event_ref MUST be called on that event. | |||
If the event is only stored OR passed through, this is not necessary | |||
(as the plugin already has 1 implicit reference). | |||
@param event An event received at an input that will not be copied to | |||
an output or stored in any way. | |||
@param context The calling context. Like event types, this is a mapped | |||
URI, see lv2_context.h. Simple plugin with just a run() method should | |||
pass 0 here (the ID of the 'standard' LV2 run context). The host | |||
guarantees that this function is realtime safe iff @a context is | |||
realtime safe. | |||
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. | |||
*/ | |||
uint32_t (*lv2_event_ref)(LV2_Event_Callback_Data callback_data, | |||
LV2_Event* event); | |||
/** | |||
Drop a reference to a non-POD event. | |||
If a plugin receives an event with type 0, it means the event is a | |||
pointer to some object in memory and not a flat sequence of bytes | |||
in the buffer. If the plugin does not pass the event through to | |||
an output or store it internally somehow, it MUST call this function | |||
on the event (more information on using non-POD events below). | |||
@param event An event received at an input that will not be copied to an | |||
output or stored in any way. | |||
@param context The calling context. Like event types, this is a mapped | |||
URI, see lv2_context.h. Simple plugin with just a run() method should | |||
pass 0 here (the ID of the 'standard' LV2 run context). The host | |||
guarantees that this function is realtime safe iff @a context is | |||
realtime safe. | |||
PLUGINS THAT VIOLATE THESE RULES MAY CAUSE CRASHES AND MEMORY LEAKS. | |||
*/ | |||
uint32_t (*lv2_event_unref)(LV2_Event_Callback_Data callback_data, | |||
LV2_Event* event); | |||
} LV2_Event_Feature; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_EVENT_H */ |
@@ -0,0 +1,37 @@ | |||
/* | |||
LV2 Instance Access Extension | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_INSTANCE_ACCESS_H | |||
#define LV2_INSTANCE_ACCESS_H | |||
#define LV2_INSTANCE_ACCESS_URI "http://lv2plug.in/ns/ext/instance-access" | |||
/** | |||
@file instance-access.h | |||
C header for the LV2 Instance Access extension | |||
<http://lv2plug.in/ns/ext/instance-access>. | |||
This extension defines a method for (e.g.) plugin UIs to get a direct | |||
handle to an LV2 plugin instance (LV2_Handle), if possible. | |||
To support this feature the host must pass an LV2_Feature struct to the | |||
UI instantiate method with URI "http://lv2plug.in/ns/ext/instance-access" | |||
and data pointed directly to the LV2_Handle of the plugin instance. | |||
*/ | |||
#endif /* LV2_INSTANCE_ACCESS_H */ | |||
@@ -0,0 +1,99 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file log.h C header for the LV2 Log extension | |||
<http://lv2plug.in/ns/ext/log>. | |||
*/ | |||
#ifndef LV2_LOG_H | |||
#define LV2_LOG_H | |||
#define LV2_LOG_URI "http://lv2plug.in/ns/ext/log" | |||
#define LV2_LOG_PREFIX LV2_LOG_URI "#" | |||
#define LV2_LOG__Entry LV2_LOG_PREFIX "Entry" | |||
#define LV2_LOG__Error LV2_LOG_PREFIX "Error" | |||
#define LV2_LOG__Note LV2_LOG_PREFIX "Note" | |||
#define LV2_LOG__Trace LV2_LOG_PREFIX "Trace" | |||
#define LV2_LOG__Warning LV2_LOG_PREFIX "Warning" | |||
#define LV2_LOG__log LV2_LOG_PREFIX "log" | |||
#include <stdarg.h> | |||
#include "urid.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#ifdef __GNUC__ | |||
/** Allow type checking of printf-like functions. */ | |||
# define LV2_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) | |||
#else | |||
# define LV2_LOG_FUNC(fmt, arg1) | |||
#endif | |||
/** | |||
Opaque data to host data for LV2_Log_Log. | |||
*/ | |||
typedef void* LV2_Log_Handle; | |||
/** | |||
Log feature (LV2_LOG__log) | |||
*/ | |||
typedef struct _LV2_Log { | |||
/** | |||
Opaque pointer to host data. | |||
This MUST be passed to methods in this struct whenever they are called. | |||
Otherwise, it must not be interpreted in any way. | |||
*/ | |||
LV2_Log_Handle handle; | |||
/** | |||
Log a message, passing format parameters directly. | |||
The API of this function matches that of the standard C printf function, | |||
except for the addition of the first two parameters. This function may | |||
be called from any non-realtime context, or from any context if @p type | |||
is @ref LV2_LOG__Trace. | |||
*/ | |||
LV2_LOG_FUNC(3, 4) | |||
int (*printf)(LV2_Log_Handle handle, | |||
LV2_URID type, | |||
const char* fmt, ...); | |||
/** | |||
Log a message, passing format parameters in a va_list. | |||
The API of this function matches that of the standard C vprintf | |||
function, except for the addition of the first two parameters. This | |||
function may be called from any non-realtime context, or from any | |||
context if @p type is @ref LV2_LOG__Trace. | |||
*/ | |||
LV2_LOG_FUNC(3, 0) | |||
int (*vprintf)(LV2_Log_Handle handle, | |||
LV2_URID type, | |||
const char* fmt, | |||
va_list ap); | |||
} LV2_Log_Log; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_LOG_H */ |
@@ -0,0 +1,145 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file logger.h Convenience API for easy logging in plugin code. | |||
This file provides simple wrappers for the most common log operations for | |||
use in plugin implementations. If host support for logging is not | |||
available, then these functions will print to stderr instead. | |||
This header is non-normative, it is provided for convenience. | |||
*/ | |||
#ifndef LV2_ATOM_LOGGER_H | |||
#define LV2_ATOM_LOGGER_H | |||
#include <stdio.h> | |||
#include "log.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
Logger convenience API state. | |||
*/ | |||
typedef struct { | |||
LV2_Log_Log* log; | |||
LV2_URID Error; | |||
LV2_URID Note; | |||
LV2_URID Trace; | |||
LV2_URID Warning; | |||
} LV2_Log_Logger; | |||
/** | |||
Initialise @p logger. | |||
URIs will be mapped using @p map and stored, a reference to @p map itself is | |||
not held. Both @p map and @p log may be NULL when unsupported by the host, | |||
in which case the implementation will fall back to printing to stderr. | |||
*/ | |||
static inline void | |||
lv2_log_logger_init(LV2_Log_Logger* logger, | |||
LV2_URID_Map* map, | |||
LV2_Log_Log* log) | |||
{ | |||
memset(logger, 0, sizeof(LV2_Log_Logger)); | |||
logger->log = log; | |||
if (map) { | |||
logger->Error = map->map(map->handle, LV2_LOG__Error); | |||
logger->Note = map->map(map->handle, LV2_LOG__Note); | |||
logger->Trace = map->map(map->handle, LV2_LOG__Trace); | |||
logger->Warning = map->map(map->handle, LV2_LOG__Warning); | |||
} | |||
} | |||
/** | |||
Log a message to the host, or stderr if support is unavailable. | |||
*/ | |||
LV2_LOG_FUNC(3, 0) | |||
static inline int | |||
lv2_log_vprintf(LV2_Log_Logger* logger, | |||
LV2_URID type, | |||
const char* fmt, | |||
va_list args) | |||
{ | |||
if (logger->log) { | |||
return logger->log->vprintf(logger->log->handle, type, fmt, args); | |||
} else { | |||
return vfprintf(stderr, fmt, args); | |||
} | |||
} | |||
/** Log an error via lv2_log_vprintf(). */ | |||
LV2_LOG_FUNC(2, 3) | |||
static inline int | |||
lv2_log_error(LV2_Log_Logger* logger, const char* fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
const int ret = lv2_log_vprintf(logger, logger->Error, fmt, args); | |||
va_end(args); | |||
return ret; | |||
} | |||
/** Log a note via lv2_log_vprintf(). */ | |||
LV2_LOG_FUNC(2, 3) | |||
static inline int | |||
lv2_log_note(LV2_Log_Logger* logger, const char* fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
const int ret = lv2_log_vprintf(logger, logger->Note, fmt, args); | |||
va_end(args); | |||
return ret; | |||
} | |||
/** Log a trace via lv2_log_vprintf(). */ | |||
LV2_LOG_FUNC(2, 3) | |||
static inline int | |||
lv2_log_trace(LV2_Log_Logger* logger, const char* fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
const int ret = lv2_log_vprintf(logger, logger->Trace, fmt, args); | |||
va_end(args); | |||
return ret; | |||
} | |||
/** Log a warning via lv2_log_vprintf(). */ | |||
LV2_LOG_FUNC(2, 3) | |||
static inline int | |||
lv2_log_warning(LV2_Log_Logger* logger, const char* fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
const int ret = lv2_log_vprintf(logger, logger->Warning, fmt, args); | |||
va_end(args); | |||
return ret; | |||
} | |||
/** | |||
@} | |||
*/ | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_LOG_LOGGER_H */ |
@@ -0,0 +1,98 @@ | |||
/**************************************************************************** | |||
lv2-midifunctions.h - support file for using MIDI in LV2 plugins | |||
Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2 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 Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA | |||
****************************************************************************/ | |||
#ifndef LV2_MIDIFUNCTIONS | |||
#define LV2_MIDIFUNCTIONS | |||
#include "lv2-miditype.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
typedef struct { | |||
LV2_MIDI* midi; | |||
uint32_t frame_count; | |||
uint32_t position; | |||
} LV2_MIDIState; | |||
inline double lv2midi_get_event(LV2_MIDIState* state, | |||
double* timestamp, | |||
uint32_t* size, | |||
unsigned char** data) { | |||
if (state->position >= state->midi->size) { | |||
state->position = state->midi->size; | |||
*timestamp = state->frame_count; | |||
*size = 0; | |||
*data = NULL; | |||
return *timestamp; | |||
} | |||
*timestamp = *(double*)(state->midi->data + state->position); | |||
*size = *(size_t*)(state->midi->data + state->position + sizeof(double)); | |||
*data = state->midi->data + state->position + | |||
sizeof(double) + sizeof(size_t); | |||
return *timestamp; | |||
} | |||
inline double lv2midi_step(LV2_MIDIState* state) { | |||
if (state->position >= state->midi->size) { | |||
state->position = state->midi->size; | |||
return state->frame_count; | |||
} | |||
state->position += sizeof(double); | |||
size_t size = *(size_t*)(state->midi->data + state->position); | |||
state->position += sizeof(size_t); | |||
state->position += size; | |||
return *(double*)(state->midi->data + state->position); | |||
} | |||
inline void lv2midi_put_event(LV2_MIDIState* state, | |||
double timestamp, | |||
uint32_t size, | |||
const unsigned char* data) { | |||
if (state->midi->size + sizeof(double) + sizeof(size_t) + size < state->midi->capacity) | |||
{ | |||
*((double*)(state->midi->data + state->midi->size)) = timestamp; | |||
state->midi->size += sizeof(double); | |||
*((size_t*)(state->midi->data + state->midi->size)) = size; | |||
state->midi->size += sizeof(size_t); | |||
memcpy(state->midi->data + state->midi->size, data, size); | |||
state->midi->size += size; | |||
state->midi->event_count++; | |||
} | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif | |||
@@ -0,0 +1,175 @@ | |||
/**************************************************************************** | |||
lv2-miditype.h - header file for using MIDI in LV2 plugins | |||
Copyright (C) 2006 Lars Luthman <lars.luthman@gmail.com> | |||
This program is free software; you can redistribute it and/or modify | |||
it under the terms of the GNU Lesser General Public License as published by | |||
the Free Software Foundation; either version 2 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 Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public License | |||
along with this program; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 01222-1307 USA | |||
****************************************************************************/ | |||
#ifndef LV2_MIDITYPE_H | |||
#define LV2_MIDITYPE_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** This data structure is used to contain the MIDI events for one run() | |||
cycle. The port buffer for a LV2 port that has the datatype | |||
<http://ll-plugins.nongnu.org/lv2/ext/miditype> should be a pointer | |||
to an instance of this struct. | |||
To store two Note On events on MIDI channel 0 in a buffer, with timestamps | |||
12 and 35.5, you could use something like this code (assuming that | |||
midi_data is a variable of type LV2_MIDI): | |||
@code | |||
size_t buffer_offset = 0; | |||
*(double*)(midi_data->data + buffer_offset) = 12; | |||
buffer_offset += sizeof(double); | |||
*(size_t*)(midi_data->data + buffer_offset) = 3; | |||
buffer_offset += sizeof(size_t); | |||
midi_data->data[buffer_offset++] = 0x90; | |||
midi_data->data[buffer_offset++] = 0x48; | |||
midi_data->data[buffer_offset++] = 0x64; | |||
++midi_data->event_count; | |||
*(double*)(midi_data->data + buffer_offset) = 35.5; | |||
buffer_offset += sizeof(double); | |||
*(size_t*)(midi_data->data + buffer_offset) = 3; | |||
buffer_offset += sizeof(size_t); | |||
midi_data->data[buffer_offset++] = 0x90; | |||
midi_data->data[buffer_offset++] = 0x55; | |||
midi_data->data[buffer_offset++] = 0x64; | |||
++midi_data->event_count; | |||
midi_data->size = buffer_offset; | |||
@endcode | |||
This would be done by the host in the case of an input port, and by the | |||
plugin in the case of an output port. Whoever is writing events to the | |||
buffer must also take care not to exceed the capacity of the data buffer. | |||
To read events from a buffer, you could do something like this: | |||
@code | |||
size_t buffer_offset = 0; | |||
uint32_t i; | |||
for (i = 0; i < midi_data->event_count; ++i) { | |||
double timestamp = *(double*)(midi_data->data + buffer_offset); | |||
buffer_offset += sizeof(double); | |||
size_t size = *(size_t*)(midi_data->data + buffer_offset); | |||
buffer_offset += sizeof(size_t); | |||
do_something_with_event(timestamp, size, | |||
midi_data->data + buffer_offset); | |||
buffer_offset += size; | |||
} | |||
@endcode | |||
*/ | |||
typedef struct { | |||
/** The number of MIDI events in the data buffer. | |||
INPUT PORTS: It's the host's responsibility to set this field to the | |||
number of MIDI events contained in the data buffer before calling the | |||
plugin's run() function. The plugin may not change this field. | |||
OUTPUT PORTS: It's the plugin's responsibility to set this field to the | |||
number of MIDI events it has stored in the data buffer before returning | |||
from the run() function. Any initial value should be ignored by the | |||
plugin. | |||
*/ | |||
uint32_t event_count; | |||
/** The size of the data buffer in bytes. It is set by the host and may not | |||
be changed by the plugin. The host is allowed to change this between | |||
run() calls. | |||
*/ | |||
uint32_t capacity; | |||
/** The size of the initial part of the data buffer that actually contains | |||
data. | |||
INPUT PORTS: It's the host's responsibility to set this field to the | |||
number of bytes used by all MIDI events it has written to the buffer | |||
(including timestamps and size fields) before calling the plugin's | |||
run() function. The plugin may not change this field. | |||
OUTPUT PORTS: It's the plugin's responsibility to set this field to | |||
the number of bytes used by all MIDI events it has written to the | |||
buffer (including timestamps and size fields) before returning from | |||
the run() function. Any initial value should be ignored by the plugin. | |||
*/ | |||
uint32_t size; | |||
/** The data buffer that is used to store MIDI events. The events are packed | |||
after each other, and the format of each event is as follows: | |||
First there is a timestamp, which should have the type "double", | |||
i.e. have the same bit size as a double and the same bit layout as a | |||
double (whatever that is on the current platform). This timestamp gives | |||
the offset from the beginning of the current cycle, in frames, that | |||
the MIDI event occurs on. It must be strictly smaller than the 'nframes' | |||
parameter to the current run() call. The MIDI events in the buffer must | |||
be ordered by their timestamp, e.g. an event with a timestamp of 123.23 | |||
must be stored after an event with a timestamp of 65.0. | |||
The second part of the event is a size field, which should have the type | |||
"size_t" (as defined in the standard C header stddef.h). It should | |||
contain the size of the MIDI data for this event, i.e. the number of | |||
bytes used to store the actual MIDI event. The bytes used by the | |||
timestamp and the size field should not be counted. | |||
The third part of the event is the actual MIDI data. There are some | |||
requirements that must be followed: | |||
* Running status is not allowed. Every event must have its own status | |||
byte. | |||
* Note On events with velocity 0 are not allowed. These events are | |||
equivalent to Note Off in standard MIDI streams, but in order to make | |||
plugins and hosts easier to write, as well as more efficient, only | |||
proper Note Off events are allowed as Note Off. | |||
* "Realtime events" (status bytes 0xF8 to 0xFF) are allowed, but may not | |||
occur inside other events like they are allowed to in hardware MIDI | |||
streams. | |||
* All events must be fully contained in a single data buffer, i.e. events | |||
may not "wrap around" by storing the first few bytes in one buffer and | |||
then wait for the next run() call to store the rest of the event. If | |||
there isn't enough space in the current data buffer to store an event, | |||
the event will either have to wait until next run() call, be ignored, | |||
or compensated for in some more clever way. | |||
* All events must be valid MIDI events. This means for example that | |||
only the first byte in each event (the status byte) may have the eighth | |||
bit set, that Note On and Note Off events are always 3 bytes long etc. | |||
The MIDI writer (host or plugin) is responsible for writing valid MIDI | |||
events to the buffer, and the MIDI reader (plugin or host) can assume | |||
that all events are valid. | |||
On a platform where double is 8 bytes and size_t is 4 bytes, the data | |||
buffer layout for a 3-byte event followed by a 4-byte event may look | |||
something like this: | |||
_______________________________________________________________ | |||
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ... | |||
|TIMESTAMP 1 |SIZE 1 |DATA |TIMESTAMP 2 |SIZE 2 |DATA | ... | |||
*/ | |||
unsigned char* data; | |||
} LV2_MIDI; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif |
@@ -0,0 +1,454 @@ | |||
/* | |||
LV2 - An audio plugin interface specification. | |||
Copyright 2006-2012 Steve Harris, David Robillard. | |||
Based on LADSPA, Copyright 2000-2002 Richard W.E. Furse, | |||
Paul Barton-Davis, Stefan Westerfeld. | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file lv2.h | |||
API for the LV2 specification <http://lv2plug.in/ns/lv2core>. | |||
Revision: 6.5 | |||
*/ | |||
#ifndef LV2_H_INCLUDED | |||
#define LV2_H_INCLUDED | |||
#include <stdint.h> | |||
#define LV2_CORE_URI "http://lv2plug.in/ns/lv2core" | |||
#define LV2_CORE_PREFIX LV2_CORE_URI "#" | |||
#define LV2_CORE__AllpassPlugin LV2_CORE_PREFIX "AllpassPlugin" | |||
#define LV2_CORE__AmplifierPlugin LV2_CORE_PREFIX "AmplifierPlugin" | |||
#define LV2_CORE__AnalyserPlugin LV2_CORE_PREFIX "AnalyserPlugin" | |||
#define LV2_CORE__AudioPort LV2_CORE_PREFIX "AudioPort" | |||
#define LV2_CORE__BandpassPlugin LV2_CORE_PREFIX "BandpassPlugin" | |||
#define LV2_CORE__CVPort LV2_CORE_PREFIX "CVPort" | |||
#define LV2_CORE__ChorusPlugin LV2_CORE_PREFIX "ChorusPlugin" | |||
#define LV2_CORE__CombPlugin LV2_CORE_PREFIX "CombPlugin" | |||
#define LV2_CORE__CompressorPlugin LV2_CORE_PREFIX "CompressorPlugin" | |||
#define LV2_CORE__ConstantPlugin LV2_CORE_PREFIX "ConstantPlugin" | |||
#define LV2_CORE__ControlPort LV2_CORE_PREFIX "ControlPort" | |||
#define LV2_CORE__ConverterPlugin LV2_CORE_PREFIX "ConverterPlugin" | |||
#define LV2_CORE__DelayPlugin LV2_CORE_PREFIX "DelayPlugin" | |||
#define LV2_CORE__DistortionPlugin LV2_CORE_PREFIX "DistortionPlugin" | |||
#define LV2_CORE__DynamicsPlugin LV2_CORE_PREFIX "DynamicsPlugin" | |||
#define LV2_CORE__EQPlugin LV2_CORE_PREFIX "EQPlugin" | |||
#define LV2_CORE__EnvelopePlugin LV2_CORE_PREFIX "EnvelopePlugin" | |||
#define LV2_CORE__ExpanderPlugin LV2_CORE_PREFIX "ExpanderPlugin" | |||
#define LV2_CORE__ExtensionData LV2_CORE_PREFIX "ExtensionData" | |||
#define LV2_CORE__Feature LV2_CORE_PREFIX "Feature" | |||
#define LV2_CORE__FilterPlugin LV2_CORE_PREFIX "FilterPlugin" | |||
#define LV2_CORE__FlangerPlugin LV2_CORE_PREFIX "FlangerPlugin" | |||
#define LV2_CORE__FunctionPlugin LV2_CORE_PREFIX "FunctionPlugin" | |||
#define LV2_CORE__GatePlugin LV2_CORE_PREFIX "GatePlugin" | |||
#define LV2_CORE__GeneratorPlugin LV2_CORE_PREFIX "GeneratorPlugin" | |||
#define LV2_CORE__HighpassPlugin LV2_CORE_PREFIX "HighpassPlugin" | |||
#define LV2_CORE__InputPort LV2_CORE_PREFIX "InputPort" | |||
#define LV2_CORE__InstrumentPlugin LV2_CORE_PREFIX "InstrumentPlugin" | |||
#define LV2_CORE__LimiterPlugin LV2_CORE_PREFIX "LimiterPlugin" | |||
#define LV2_CORE__LowpassPlugin LV2_CORE_PREFIX "LowpassPlugin" | |||
#define LV2_CORE__MixerPlugin LV2_CORE_PREFIX "MixerPlugin" | |||
#define LV2_CORE__ModulatorPlugin LV2_CORE_PREFIX "ModulatorPlugin" | |||
#define LV2_CORE__MultiEQPlugin LV2_CORE_PREFIX "MultiEQPlugin" | |||
#define LV2_CORE__OscillatorPlugin LV2_CORE_PREFIX "OscillatorPlugin" | |||
#define LV2_CORE__OutputPort LV2_CORE_PREFIX "OutputPort" | |||
#define LV2_CORE__ParaEQPlugin LV2_CORE_PREFIX "ParaEQPlugin" | |||
#define LV2_CORE__PhaserPlugin LV2_CORE_PREFIX "PhaserPlugin" | |||
#define LV2_CORE__PitchPlugin LV2_CORE_PREFIX "PitchPlugin" | |||
#define LV2_CORE__Plugin LV2_CORE_PREFIX "Plugin" | |||
#define LV2_CORE__PluginBase LV2_CORE_PREFIX "PluginBase" | |||
#define LV2_CORE__Point LV2_CORE_PREFIX "Point" | |||
#define LV2_CORE__Port LV2_CORE_PREFIX "Port" | |||
#define LV2_CORE__PortProperty LV2_CORE_PREFIX "PortProperty" | |||
#define LV2_CORE__Resource LV2_CORE_PREFIX "Resource" | |||
#define LV2_CORE__ReverbPlugin LV2_CORE_PREFIX "ReverbPlugin" | |||
#define LV2_CORE__ScalePoint LV2_CORE_PREFIX "ScalePoint" | |||
#define LV2_CORE__SimulatorPlugin LV2_CORE_PREFIX "SimulatorPlugin" | |||
#define LV2_CORE__SpatialPlugin LV2_CORE_PREFIX "SpatialPlugin" | |||
#define LV2_CORE__Specification LV2_CORE_PREFIX "Specification" | |||
#define LV2_CORE__SpectralPlugin LV2_CORE_PREFIX "SpectralPlugin" | |||
#define LV2_CORE__UtilityPlugin LV2_CORE_PREFIX "UtilityPlugin" | |||
#define LV2_CORE__WaveshaperPlugin LV2_CORE_PREFIX "WaveshaperPlugin" | |||
#define LV2_CORE__appliesTo LV2_CORE_PREFIX "appliesTo" | |||
#define LV2_CORE__binary LV2_CORE_PREFIX "binary" | |||
#define LV2_CORE__connectionOptional LV2_CORE_PREFIX "connectionOptional" | |||
#define LV2_CORE__control LV2_CORE_PREFIX "control" | |||
#define LV2_CORE__default LV2_CORE_PREFIX "default" | |||
#define LV2_CORE__designation LV2_CORE_PREFIX "designation" | |||
#define LV2_CORE__documentation LV2_CORE_PREFIX "documentation" | |||
#define LV2_CORE__enumeration LV2_CORE_PREFIX "enumeration" | |||
#define LV2_CORE__extensionData LV2_CORE_PREFIX "extensionData" | |||
#define LV2_CORE__freeWheeling LV2_CORE_PREFIX "freeWheeling" | |||
#define LV2_CORE__hardRTCapable LV2_CORE_PREFIX "hardRTCapable" | |||
#define LV2_CORE__inPlaceBroken LV2_CORE_PREFIX "inPlaceBroken" | |||
#define LV2_CORE__index LV2_CORE_PREFIX "index" | |||
#define LV2_CORE__integer LV2_CORE_PREFIX "integer" | |||
#define LV2_CORE__isLive LV2_CORE_PREFIX "isLive" | |||
#define LV2_CORE__latency LV2_CORE_PREFIX "latency" | |||
#define LV2_CORE__maximum LV2_CORE_PREFIX "maximum" | |||
#define LV2_CORE__microVersion LV2_CORE_PREFIX "microVersion" | |||
#define LV2_CORE__minimum LV2_CORE_PREFIX "minimum" | |||
#define LV2_CORE__minorVersion LV2_CORE_PREFIX "minorVersion" | |||
#define LV2_CORE__name LV2_CORE_PREFIX "name" | |||
#define LV2_CORE__optionalFeature LV2_CORE_PREFIX "optionalFeature" | |||
#define LV2_CORE__port LV2_CORE_PREFIX "port" | |||
#define LV2_CORE__portProperty LV2_CORE_PREFIX "portProperty" | |||
#define LV2_CORE__project LV2_CORE_PREFIX "project" | |||
#define LV2_CORE__reportsLatency LV2_CORE_PREFIX "reportsLatency" | |||
#define LV2_CORE__requiredFeature LV2_CORE_PREFIX "requiredFeature" | |||
#define LV2_CORE__sampleRate LV2_CORE_PREFIX "sampleRate" | |||
#define LV2_CORE__scalePoint LV2_CORE_PREFIX "scalePoint" | |||
#define LV2_CORE__symbol LV2_CORE_PREFIX "symbol" | |||
#define LV2_CORE__toggled LV2_CORE_PREFIX "toggled" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
Plugin Instance Handle. | |||
This is a handle for one particular instance of a plugin. It is valid to | |||
compare to NULL (or 0 for C++) but otherwise the host MUST NOT attempt to | |||
interpret it. | |||
*/ | |||
typedef void * LV2_Handle; | |||
/** | |||
Feature. | |||
Features allow hosts to make additional functionality available to plugins | |||
without requiring modification to the LV2 API. Extensions may define new | |||
features and specify the @ref URI and @ref data to be used if necessary. | |||
Some features, such as lv2:isLive, do not require the host to pass data. | |||
*/ | |||
typedef struct _LV2_Feature { | |||
/** | |||
A globally unique, case-sensitive identifier (URI) for this feature. | |||
This MUST be a valid URI string as defined by RFC 3986. | |||
*/ | |||
const char * URI; | |||
/** | |||
Pointer to arbitrary data. | |||
The format of this data is defined by the extension which describes the | |||
feature with the given @ref URI. | |||
*/ | |||
void * data; | |||
} LV2_Feature; | |||
/** | |||
Plugin Descriptor. | |||
This structure provides the core functions necessary to instantiate and use | |||
a plugin. | |||
*/ | |||
typedef struct _LV2_Descriptor { | |||
/** | |||
A globally unique, case-sensitive identifier for this plugin. | |||
This MUST be a valid URI string as defined by RFC 3986. All plugins with | |||
the same URI MUST be compatible to some degree, see | |||
http://lv2plug.in/ns/lv2core for details. | |||
*/ | |||
const char * URI; | |||
/** | |||
Instantiate the plugin. | |||
Note that instance initialisation should generally occur in activate() | |||
rather than here. If a host calls instantiate(), it MUST call cleanup() | |||
at some point in the future. | |||
@param descriptor Descriptor of the plugin to instantiate. | |||
@param sample_rate Sample rate, in Hz, for the new plugin instance. | |||
@param bundle_path Path to the LV2 bundle which contains this plugin | |||
binary. It MUST include the trailing directory separator (e.g. '/') so | |||
that simply appending a filename will yield the path to that file in the | |||
bundle. | |||
@param features A NULL terminated array of LV2_Feature structs which | |||
represent the features the host supports. Plugins may refuse to | |||
instantiate if required features are not found here. However, hosts MUST | |||
NOT use this as a discovery mechanism: instead, use the RDF data to | |||
determine which features are required and do not attempt to instantiate | |||
unsupported plugins at all. This parameter MUST NOT be NULL, i.e. a host | |||
that supports no features MUST pass a single element array containing | |||
NULL. | |||
@return A handle for the new plugin instance, or NULL if instantiation | |||
has failed. | |||
*/ | |||
LV2_Handle (*instantiate)(const struct _LV2_Descriptor * descriptor, | |||
double sample_rate, | |||
const char * bundle_path, | |||
const LV2_Feature *const * features); | |||
/** | |||
Connect a port on a plugin instance to a memory location. | |||
Plugin writers should be aware that the host may elect to use the same | |||
buffer for more than one port and even use the same buffer for both | |||
input and output (see lv2:inPlaceBroken in lv2.ttl). | |||
If the plugin has the feature lv2:hardRTCapable then there are various | |||
things that the plugin MUST NOT do within the connect_port() function; | |||
see lv2core.ttl for details. | |||
connect_port() MUST be called at least once for each port before run() | |||
is called, unless that port is lv2:connectionOptional. The plugin must | |||
pay careful attention to the block size passed to run() since the block | |||
allocated may only just be large enough to contain the data, and is not | |||
guaranteed to remain constant between run() calls. | |||
connect_port() may be called more than once for a plugin instance to | |||
allow the host to change the buffers that the plugin is reading or | |||
writing. These calls may be made before or after activate() or | |||
deactivate() calls. | |||
@param instance Plugin instance containing the port. | |||
@param port Index of the port to connect. The host MUST NOT try to | |||
connect a port index that is not defined in the plugin's RDF data. If | |||
it does, the plugin's behaviour is undefined (a crash is likely). | |||
@param data_location Pointer to data of the type defined by the port | |||
type in the plugin's RDF data (e.g. an array of float for an | |||
lv2:AudioPort). This pointer must be stored by the plugin instance and | |||
used to read/write data when run() is called. Data present at the time | |||
of the connect_port() call MUST NOT be considered meaningful. | |||
*/ | |||
void (*connect_port)(LV2_Handle instance, | |||
uint32_t port, | |||
void * data_location); | |||
/** | |||
Initialise a plugin instance and activate it for use. | |||
This is separated from instantiate() to aid real-time support and so | |||
that hosts can reinitialise a plugin instance by calling deactivate() | |||
and then activate(). In this case the plugin instance MUST reset all | |||
state information dependent on the history of the plugin instance except | |||
for any data locations provided by connect_port(). If there is nothing | |||
for activate() to do then this field may be NULL. | |||
When present, hosts MUST call this function once before run() is called | |||
for the first time. This call SHOULD be made as close to the run() call | |||
as possible and indicates to real-time plugins that they are now live, | |||
however plugins MUST NOT rely on a prompt call to run() after | |||
activate(). | |||
The host MUST NOT call activate() again until deactivate() has been | |||
called first. If a host calls activate(), it MUST call deactivate() at | |||
some point in the future. Note that connect_port() may be called before | |||
or after activate(). | |||
*/ | |||
void (*activate)(LV2_Handle instance); | |||
/** | |||
Run a plugin instance for a block. | |||
Note that if an activate() function exists then it must be called before | |||
run(). If deactivate() is called for a plugin instance then run() may | |||
not be called until activate() has been called again. | |||
If the plugin has the feature lv2:hardRTCapable then there are various | |||
things that the plugin MUST NOT do within the run() function (see | |||
lv2core.ttl for details). | |||
As a special case, when @p sample_count == 0, the plugin should update | |||
any output ports that represent a single instant in time (e.g. control | |||
ports, but not audio ports). This is particularly useful for latent | |||
plugins, which should update their latency output port so hosts can | |||
pre-roll plugins to compute latency. Plugins MUST NOT crash when | |||
@p sample_count == 0. | |||
@param instance Instance to be run. | |||
@param sample_count The block size (in samples) for which the plugin | |||
instance must run. | |||
*/ | |||
void (*run)(LV2_Handle instance, | |||
uint32_t sample_count); | |||
/** | |||
Deactivate a plugin instance (counterpart to activate()). | |||
Hosts MUST deactivate all activated instances after they have been run() | |||
for the last time. This call SHOULD be made as close to the last run() | |||
call as possible and indicates to real-time plugins that they are no | |||
longer live, however plugins MUST NOT rely on prompt deactivation. If | |||
there is nothing for deactivate() to do then this field may be NULL | |||
Deactivation is not similar to pausing since the plugin instance will be | |||
reinitialised by activate(). However, deactivate() itself MUST NOT fully | |||
reset plugin state. For example, the host may deactivate a plugin, then | |||
store its state (using some extension to do so). | |||
Hosts MUST NOT call deactivate() unless activate() was previously | |||
called. Note that connect_port() may be called before or after | |||
deactivate(). | |||
*/ | |||
void (*deactivate)(LV2_Handle instance); | |||
/** | |||
Clean up a plugin instance (counterpart to instantiate()). | |||
Once an instance of a plugin has been finished with it must be deleted | |||
using this function. The instance handle passed ceases to be valid after | |||
this call. | |||
If activate() was called for a plugin instance then a corresponding call | |||
to deactivate() MUST be made before cleanup() is called. Hosts MUST NOT | |||
call cleanup() unless instantiate() was previously called. | |||
*/ | |||
void (*cleanup)(LV2_Handle instance); | |||
/** | |||
Return additional plugin data defined by some extenion. | |||
A typical use of this facility is to return a struct containing function | |||
pointers to extend the LV2_Descriptor API. | |||
The actual type and meaning of the returned object MUST be specified | |||
precisely by the extension. This function MUST return NULL for any | |||
unsupported URI. If a plugin does not support any extension data, this | |||
field may be NULL. | |||
The host is never responsible for freeing the returned value. | |||
*/ | |||
const void * (*extension_data)(const char * uri); | |||
} LV2_Descriptor; | |||
/** | |||
Put this (LV2_SYMBOL_EXPORT) before any functions that are to be loaded | |||
by the host as a symbol from the dynamic library. | |||
*/ | |||
#ifdef _WIN32 | |||
# define LV2_SYMBOL_EXPORT __declspec(dllexport) | |||
#else | |||
# define LV2_SYMBOL_EXPORT | |||
#endif | |||
/** | |||
Prototype for plugin accessor function. | |||
This is part of the old discovery API, which has been replaced due to being | |||
inadequate for some plugins. It is limited because the bundle path is not | |||
available during discovery, and it relies on non-portable shared library | |||
constructors/destructors. However, this API is still supported and plugins | |||
are not required to migrate. | |||
Plugins are discovered by hosts using RDF data (not by loading libraries). | |||
See http://lv2plug.in for details on the discovery process, though most | |||
hosts should use an existing library to implement this functionality. | |||
A plugin library MUST include a function called "lv2_descriptor" with this | |||
prototype. This function MUST have C-style linkage (if you are using C++ | |||
this is taken care of by the 'extern "C"' clause at the top of this file). | |||
When it is time to load a plugin (designated by its URI), the host loads the | |||
plugin's library, gets the lv2_descriptor() function from it, and uses this | |||
function to find the LV2_Descriptor for the desired plugin. Plugins are | |||
accessed by index using values from 0 upwards. This function MUST return | |||
NULL for out of range indices, so the host can enumerate plugins by | |||
increasing @p index until NULL is returned. | |||
Note that @p index has no meaning, hosts MUST NOT depend on it remaining | |||
consistent between loads of the plugin library. | |||
*/ | |||
LV2_SYMBOL_EXPORT | |||
const LV2_Descriptor * lv2_descriptor(uint32_t index); | |||
/** | |||
Type of the lv2_descriptor() function in a library (old discovery API). | |||
*/ | |||
typedef const LV2_Descriptor * | |||
(*LV2_Descriptor_Function)(uint32_t index); | |||
/** | |||
Handle for a library descriptor. | |||
*/ | |||
typedef void* LV2_Lib_Handle; | |||
/** | |||
Descriptor for a plugin library. | |||
To access a plugin library, the host creates an LV2_Lib_Descriptor via the | |||
lv2_lib_descriptor() function in the shared object. | |||
*/ | |||
typedef struct { | |||
/** | |||
Opaque library data which must be passed as the first parameter to all | |||
the methods of this struct. | |||
*/ | |||
LV2_Lib_Handle handle; | |||
/** | |||
The total size of this struct. This allows for this struct to be | |||
expanded in the future if necessary. This MUST be set by the library to | |||
sizeof(LV2_Lib_Descriptor). The host MUST NOT access any fields of this | |||
struct beyond get_plugin() unless this field indicates they are present. | |||
*/ | |||
uint32_t size; | |||
/** | |||
Destroy this library descriptor and free all related resources. | |||
*/ | |||
void (*cleanup)(LV2_Lib_Handle handle); | |||
/** | |||
Plugin accessor. | |||
Plugins are accessed by index using values from 0 upwards. Out of range | |||
indices MUST result in this function returning NULL, so the host can | |||
enumerate plugins by increasing @a index until NULL is returned. | |||
*/ | |||
const LV2_Descriptor * (*get_plugin)(LV2_Lib_Handle handle, | |||
uint32_t index); | |||
} LV2_Lib_Descriptor; | |||
/** | |||
Prototype for library accessor function. | |||
This is the entry point for a plugin library. Hosts load this symbol from | |||
the library and call this function to obtain a library descriptor which can | |||
be used to access all the contained plugins. The returned object must not | |||
be destroyed (using LV2_Lib_Descriptor::cleanup()) until all plugins loaded | |||
from that library have been destroyed. | |||
*/ | |||
const LV2_Lib_Descriptor * | |||
lv2_lib_descriptor(const char * bundle_path, | |||
const LV2_Feature *const * features); | |||
/** | |||
Type of the lv2_lib_descriptor() function in an LV2 library. | |||
*/ | |||
typedef const LV2_Lib_Descriptor * | |||
(*LV2_Lib_Descriptor_Function)(const char * bundle_path, | |||
const LV2_Feature *const * features); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* LV2_H_INCLUDED */ |
@@ -0,0 +1,107 @@ | |||
/* | |||
LV2 External UI extension | |||
This work is in public domain. | |||
This file 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. | |||
If you have questions, contact Filipe Coelho (aka falkTX) <falktx@falktx.com> | |||
or ask in #lad channel, FreeNode IRC network. | |||
*/ | |||
/** | |||
@file lv2_external_ui.h | |||
C header for the LV2 External UI extension <http://kxstudio.sf.net/ns/lv2ext/external-ui>. | |||
*/ | |||
#ifndef LV2_EXTERNAL_UI_H | |||
#define LV2_EXTERNAL_UI_H | |||
#include "ui.h" | |||
#define LV2_EXTERNAL_UI_URI "http://kxstudio.sf.net/ns/lv2ext/external-ui" | |||
#define LV2_EXTERNAL_UI_PREFIX LV2_EXTERNAL_UI_URI "#" | |||
#define LV2_EXTERNAL_UI__Host LV2_EXTERNAL_UI_PREFIX "Host" | |||
#define LV2_EXTERNAL_UI__Widget LV2_EXTERNAL_UI_PREFIX "Widget" | |||
/** This extension used to be defined by a lv2plug.in URI */ | |||
#define LV2_EXTERNAL_UI_DEPRECATED_URI "http://lv2plug.in/ns/extensions/ui#external" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
* When LV2_EXTERNAL_UI__Widget UI is instantiated, the returned | |||
* LV2UI_Widget handle must be cast to pointer to LV2_External_UI_Widget. | |||
* UI is created in invisible state. | |||
*/ | |||
typedef struct _LV2_External_UI_Widget { | |||
/** | |||
* Host calls this function regulary. UI library implementing the | |||
* callback may do IPC or redraw the UI. | |||
* | |||
* @param _this_ the UI context | |||
*/ | |||
void (*run)(struct _LV2_External_UI_Widget * _this_); | |||
/** | |||
* Host calls this function to make the plugin UI visible. | |||
* | |||
* @param _this_ the UI context | |||
*/ | |||
void (*show)(struct _LV2_External_UI_Widget * _this_); | |||
/** | |||
* Host calls this function to make the plugin UI invisible again. | |||
* | |||
* @param _this_ the UI context | |||
*/ | |||
void (*hide)(struct _LV2_External_UI_Widget * _this_); | |||
} LV2_External_UI_Widget; | |||
#define LV2_EXTERNAL_UI_RUN(ptr) (ptr)->run(ptr) | |||
#define LV2_EXTERNAL_UI_SHOW(ptr) (ptr)->show(ptr) | |||
#define LV2_EXTERNAL_UI_HIDE(ptr) (ptr)->hide(ptr) | |||
/** | |||
* On UI instantiation, host must supply LV2_EXTERNAL_UI__Host feature. | |||
* LV2_Feature::data must be pointer to LV2_External_UI_Host. | |||
*/ | |||
typedef struct _LV2_External_UI_Host { | |||
/** | |||
* Callback that plugin UI will call | |||
* when UI (GUI window) is closed by user. | |||
* This callback will be called during execution of LV2_External_UI_Widget::run() | |||
* (i.e. not from background thread). | |||
* | |||
* After this callback is called, UI is defunct. Host must call | |||
* LV2UI_Descriptor::cleanup(). If host wants to make the UI visible | |||
* again UI must be reinstantiated. | |||
* | |||
* @param controller Host context associated with plugin UI, as | |||
* supplied to LV2UI_Descriptor::instantiate() | |||
*/ | |||
void (*ui_closed)(LV2UI_Controller controller); | |||
/** | |||
* Optional (may be NULL) "user friendly" identifier which the UI | |||
* may display to allow a user to easily associate this particular | |||
* UI instance with the correct plugin instance as it is represented | |||
* by the host (e.g. "track 1" or "channel 4"). | |||
* | |||
* If supplied by host, the string will be referenced only during | |||
* LV2UI_Descriptor::instantiate() | |||
*/ | |||
const char * plugin_human_id; | |||
} LV2_External_UI_Host; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_EXTERNAL_UI_H */ |
@@ -0,0 +1,174 @@ | |||
/* | |||
LV2 Programs Extension | |||
Copyright 2012 Filipe Coelho <falktx@falktx.com> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file lv2_programs.h | |||
C header for the LV2 programs extension <http://kxstudio.sf.net/ns/lv2ext/programs>. | |||
*/ | |||
#ifndef LV2_PROGRAMS_H | |||
#define LV2_PROGRAMS_H | |||
#include "lv2.h" | |||
#include "ui.h" | |||
#define LV2_PROGRAMS_URI "http://kxstudio.sf.net/ns/lv2ext/programs" | |||
#define LV2_PROGRAMS_PREFIX LV2_PROGRAMS_URI "#" | |||
#define LV2_PROGRAMS__Host LV2_PROGRAMS_PREFIX "Host" | |||
#define LV2_PROGRAMS__Interface LV2_PROGRAMS_PREFIX "Interface" | |||
#define LV2_PROGRAMS__UIInterface LV2_PROGRAMS_PREFIX "UIInterface" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
typedef void* LV2_Programs_Handle; | |||
typedef struct _LV2_Program_Descriptor { | |||
/** Bank number for this program. Note that this extension does not | |||
support MIDI-style separation of bank LSB and MSB values. There is | |||
no restriction on the set of available banks: the numbers do not | |||
need to be contiguous, there does not need to be a bank 0, etc. */ | |||
uint32_t bank; | |||
/** Program number (unique within its bank) for this program. There is | |||
no restriction on the set of available programs: the numbers do not | |||
need to be contiguous, there does not need to be a program 0, etc. */ | |||
uint32_t program; | |||
/** Name of the program. */ | |||
const char * name; | |||
} LV2_Program_Descriptor; | |||
/** | |||
Programs extension, plugin data. | |||
When the plugin's extension_data is called with argument LV2_PROGRAMS__Interface, | |||
the plugin MUST return an LV2_Programs_Instance structure, which remains valid | |||
for the lifetime of the plugin. | |||
*/ | |||
typedef struct _LV2_Programs_Interface { | |||
/** | |||
* get_program() | |||
* | |||
* This member is a function pointer that provides a description | |||
* of a program (named preset sound) available on this plugin. | |||
* | |||
* The index argument is an index into the plugin's list of | |||
* programs, not a program number as represented by the Program | |||
* field of the LV2_Program_Descriptor. (This distinction is | |||
* needed to support plugins that use non-contiguous program or | |||
* bank numbers.) | |||
* | |||
* This function returns a LV2_Program_Descriptor pointer that is | |||
* guaranteed to be valid only until the next call to get_program | |||
* or deactivate, on the same plugin instance. This function must | |||
* return NULL if passed an index argument out of range, so that | |||
* the host can use it to query the number of programs as well as | |||
* their properties. | |||
*/ | |||
const LV2_Program_Descriptor *(*get_program)(LV2_Handle handle, | |||
uint32_t index); | |||
/** | |||
* select_program() | |||
* | |||
* This member is a function pointer that selects a new program | |||
* for this plugin. The program change should take effect | |||
* immediately at the start of the next run() call. (This | |||
* means that a host providing the capability of changing programs | |||
* between any two notes on a track must vary the block size so as | |||
* to place the program change at the right place. A host that | |||
* wanted to avoid this would probably just instantiate a plugin | |||
* for each program.) | |||
* | |||
* Plugins should ignore a select_program() call with an invalid | |||
* bank or program. | |||
* | |||
* A plugin is not required to select any particular default | |||
* program on activate(): it's the host's duty to set a program | |||
* explicitly. | |||
* | |||
* A plugin is permitted to re-write the values of its input | |||
* control ports when select_program is called. The host should | |||
* re-read the input control port values and update its own | |||
* records appropriately. (This is the only circumstance in which | |||
* a LV2 plugin is allowed to modify its own control-input ports.) | |||
*/ | |||
void (*select_program)(LV2_Handle handle, | |||
uint32_t bank, | |||
uint32_t program); | |||
} LV2_Programs_Interface; | |||
/** | |||
Programs extension, UI data. | |||
When the UI's extension_data is called with argument LV2_PROGRAMS__UIInterface, | |||
the UI MUST return an LV2_Programs_UI_Interface structure, which remains valid | |||
for the lifetime of the UI. | |||
*/ | |||
typedef struct _LV2_Programs_UI_Interface { | |||
/** | |||
* select_program() | |||
* | |||
* This is exactly the same as select_program in LV2_Programs_Instance, | |||
* but this struct relates to the UI instead of the plugin. | |||
* | |||
* When called, UIs should update their state to match the selected program. | |||
*/ | |||
void (*select_program)(LV2UI_Handle handle, | |||
uint32_t bank, | |||
uint32_t program); | |||
} LV2_Programs_UI_Interface; | |||
/** | |||
Feature data for LV2_PROGRAMS__Host. | |||
*/ | |||
typedef struct _LV2_Programs_Host { | |||
/** | |||
* Opaque host data. | |||
*/ | |||
LV2_Programs_Handle handle; | |||
/** | |||
* program_changed() | |||
* | |||
* Tell the host to reload a plugin's program. | |||
* Parameter handle MUST be the 'handle' member of this struct. | |||
* Parameter index is program index to change. | |||
* When index is -1, host should reload all the programs. | |||
* | |||
* The plugin MUST NEVER call this function on a RT context or during run(). | |||
* | |||
* NOTE: This call is to inform the host about a program's bank, program or name change. | |||
* It DOES NOT change the current selected program. | |||
*/ | |||
void (*program_changed)(LV2_Programs_Handle handle, | |||
int32_t index); | |||
} LV2_Programs_Host; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_PROGRAMS_H */ |
@@ -0,0 +1,105 @@ | |||
/* | |||
LV2 realtime safe memory pool extension definition | |||
This work is in public domain. | |||
This file 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. | |||
If you have questions, contact Filipe Coelho (aka falkTX) <falktx@falktx.com> | |||
or ask in #lad channel, FreeNode IRC network. | |||
*/ | |||
/** | |||
* @file lv2_rtmempool.h | |||
* C header for the LV2 rtmempool extension <http://kxstudio.sf.net/ns/lv2ext/rtmempool>. | |||
* | |||
*/ | |||
#ifndef LV2_RTMEMPOOL_H | |||
#define LV2_RTMEMPOOL_H | |||
#define LV2_RTSAFE_MEMORY_POOL_URI "http://kxstudio.sf.net/ns/lv2ext/rtmempool" | |||
#define LV2_RTSAFE_MEMORY_POOL_PREFIX LV2_RTSAFE_MEMORY_POOL_URI "#" | |||
#define LV2_RTSAFE_MEMORY_POOL__Pool LV2_RTSAFE_MEMORY_POOL_URI "Pool" | |||
/** max size of memory pool name, in chars, including terminating zero char */ | |||
#define LV2_RTSAFE_MEMORY_POOL_NAME_MAX 128 | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
#include <stdbool.h> | |||
#endif | |||
/** | |||
* Opaque data to host data for LV2_RtMemPool_Pool. | |||
*/ | |||
typedef void* LV2_RtMemPool_Handle; | |||
/** | |||
* On instantiation, host must supply LV2_RTSAFE_MEMORY_POOL__Pool feature. | |||
* LV2_Feature::data must be pointer to LV2_RtMemPool_Pool. | |||
*/ | |||
typedef struct _LV2_RtMemPool_Pool { | |||
/** | |||
* This function is called when plugin wants to create memory pool | |||
* | |||
* <b>may/will sleep</b> | |||
* | |||
* @param pool_name pool name, for debug purposes, max RTSAFE_MEMORY_POOL_NAME_MAX chars, including terminating zero char. May be NULL. | |||
* @param data_size memory chunk size | |||
* @param min_preallocated min chunks preallocated | |||
* @param max_preallocated max chunks preallocated | |||
* | |||
* @return Success status, true if successful | |||
*/ | |||
bool (*create)(LV2_RtMemPool_Handle * handle_ptr, | |||
const char * pool_name, | |||
size_t data_size, | |||
size_t min_preallocated, | |||
size_t max_preallocated); | |||
/** | |||
* This function is called when plugin wants to destroy previously created memory pool | |||
* | |||
* <b>may/will sleep</b> | |||
*/ | |||
void (*destroy)(LV2_RtMemPool_Handle handle); | |||
/** | |||
* This function is called when plugin wants to allocate memory in context where sleeping is not allowed | |||
* | |||
* <b>will not sleep</b> | |||
* | |||
* @return Pointer to allocated memory or NULL if memory no memory is available | |||
*/ | |||
void * (*allocate_atomic)(LV2_RtMemPool_Handle handle); | |||
/** | |||
* This function is called when plugin wants to allocate memory in context where sleeping is allowed | |||
* | |||
* <b>may/will sleep</b> | |||
* | |||
* @return Pointer to allocated memory or NULL if memory no memory is available (should not happen under normal conditions) | |||
*/ | |||
void * (*allocate_sleepy)(LV2_RtMemPool_Handle handle); | |||
/** | |||
* This function is called when plugin wants to deallocate previously allocated memory | |||
* | |||
* <b>will not sleep</b> | |||
* | |||
* @param memory_ptr pointer to previously allocated memory chunk | |||
*/ | |||
void (*deallocate)(LV2_RtMemPool_Handle handle, | |||
void * memory_ptr); | |||
} LV2_RtMemPool_Pool; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_RTMEMPOOL_H */ |
@@ -0,0 +1,226 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file midi.h | |||
C definitions for the LV2 MIDI extension <http://lv2plug.in/ns/ext/midi>. | |||
*/ | |||
#ifndef LV2_MIDI_H | |||
#define LV2_MIDI_H | |||
#include <stdint.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
#define LV2_MIDI_URI "http://lv2plug.in/ns/ext/midi" | |||
#define LV2_MIDI_PREFIX LV2_MIDI_URI "#" | |||
#define LV2_MIDI__ActiveSense LV2_MIDI_PREFIX "ActiveSense" | |||
#define LV2_MIDI__Aftertouch LV2_MIDI_PREFIX "Aftertouch" | |||
#define LV2_MIDI__Bender LV2_MIDI_PREFIX "Bender" | |||
#define LV2_MIDI__ChannelPressure LV2_MIDI_PREFIX "ChannelPressure" | |||
#define LV2_MIDI__Chunk LV2_MIDI_PREFIX "Chunk" | |||
#define LV2_MIDI__Clock LV2_MIDI_PREFIX "Clock" | |||
#define LV2_MIDI__Continue LV2_MIDI_PREFIX "Continue" | |||
#define LV2_MIDI__Controller LV2_MIDI_PREFIX "Controller" | |||
#define LV2_MIDI__MidiEvent LV2_MIDI_PREFIX "MidiEvent" | |||
#define LV2_MIDI__NoteOff LV2_MIDI_PREFIX "NoteOff" | |||
#define LV2_MIDI__NoteOn LV2_MIDI_PREFIX "NoteOn" | |||
#define LV2_MIDI__ProgramChange LV2_MIDI_PREFIX "ProgramChange" | |||
#define LV2_MIDI__QuarterFrame LV2_MIDI_PREFIX "QuarterFrame" | |||
#define LV2_MIDI__Reset LV2_MIDI_PREFIX "Reset" | |||
#define LV2_MIDI__SongPosition LV2_MIDI_PREFIX "SongPosition" | |||
#define LV2_MIDI__SongSelect LV2_MIDI_PREFIX "SongSelect" | |||
#define LV2_MIDI__Start LV2_MIDI_PREFIX "Start" | |||
#define LV2_MIDI__Stop LV2_MIDI_PREFIX "Stop" | |||
#define LV2_MIDI__SystemCommon LV2_MIDI_PREFIX "SystemCommon" | |||
#define LV2_MIDI__SystemExclusive LV2_MIDI_PREFIX "SystemExclusive" | |||
#define LV2_MIDI__SystemMessage LV2_MIDI_PREFIX "SystemMessage" | |||
#define LV2_MIDI__SystemRealtime LV2_MIDI_PREFIX "SystemRealtime" | |||
#define LV2_MIDI__Tick LV2_MIDI_PREFIX "Tick" | |||
#define LV2_MIDI__TuneRequest LV2_MIDI_PREFIX "TuneRequest" | |||
#define LV2_MIDI__VoiceMessage LV2_MIDI_PREFIX "VoiceMessage" | |||
#define LV2_MIDI__benderValue LV2_MIDI_PREFIX "benderValue" | |||
#define LV2_MIDI__binding LV2_MIDI_PREFIX "binding" | |||
#define LV2_MIDI__byteNumber LV2_MIDI_PREFIX "byteNumber" | |||
#define LV2_MIDI__channel LV2_MIDI_PREFIX "channel" | |||
#define LV2_MIDI__chunk LV2_MIDI_PREFIX "chunk" | |||
#define LV2_MIDI__controllerNumber LV2_MIDI_PREFIX "controllerNumber" | |||
#define LV2_MIDI__controllerValue LV2_MIDI_PREFIX "controllerValue" | |||
#define LV2_MIDI__noteNumber LV2_MIDI_PREFIX "noteNumber" | |||
#define LV2_MIDI__pressure LV2_MIDI_PREFIX "pressure" | |||
#define LV2_MIDI__programNumber LV2_MIDI_PREFIX "programNumber" | |||
#define LV2_MIDI__property LV2_MIDI_PREFIX "property" | |||
#define LV2_MIDI__songNumber LV2_MIDI_PREFIX "songNumber" | |||
#define LV2_MIDI__songPosition LV2_MIDI_PREFIX "songPosition" | |||
#define LV2_MIDI__status LV2_MIDI_PREFIX "status" | |||
#define LV2_MIDI__statusMask LV2_MIDI_PREFIX "statusMask" | |||
#define LV2_MIDI__velocity LV2_MIDI_PREFIX "velocity" | |||
/** | |||
MIDI Message Type. | |||
This includes both voice messages (which have a channel) and system messages | |||
(which do not), as well as a sentinel value for invalid messages. To get | |||
the type of a message suitable for use in a switch statement, use | |||
lv2_midi_get_type() on the status byte. | |||
*/ | |||
typedef enum { | |||
LV2_MIDI_MSG_INVALID = 0, /**< Invalid Message */ | |||
LV2_MIDI_MSG_NOTE_OFF = 0x80, /**< Note Off */ | |||
LV2_MIDI_MSG_NOTE_ON = 0x90, /**< Note On */ | |||
LV2_MIDI_MSG_NOTE_PRESSURE = 0xA0, /**< Note Pressure */ | |||
LV2_MIDI_MSG_CONTROLLER = 0xB0, /**< Controller */ | |||
LV2_MIDI_MSG_PGM_CHANGE = 0xC0, /**< Program Change */ | |||
LV2_MIDI_MSG_CHANNEL_PRESSURE = 0xD0, /**< Channel Pressure */ | |||
LV2_MIDI_MSG_BENDER = 0xE0, /**< Pitch Bender */ | |||
LV2_MIDI_MSG_SYSTEM_EXCLUSIVE = 0xF0, /**< System Exclusive Begin */ | |||
LV2_MIDI_MSG_MTC_QUARTER = 0xF1, /**< MTC Quarter Frame */ | |||
LV2_MIDI_MSG_SONG_POS = 0xF2, /**< Song Position */ | |||
LV2_MIDI_MSG_SONG_SELECT = 0xF3, /**< Song Select */ | |||
LV2_MIDI_MSG_TUNE_REQUEST = 0xF6, /**< Tune Request */ | |||
LV2_MIDI_MSG_CLOCK = 0xF8, /**< Clock */ | |||
LV2_MIDI_MSG_START = 0xFA, /**< Start */ | |||
LV2_MIDI_MSG_CONTINUE = 0xFB, /**< Continue */ | |||
LV2_MIDI_MSG_STOP = 0xFC, /**< Stop */ | |||
LV2_MIDI_MSG_ACTIVE_SENSE = 0xFE, /**< Active Sensing */ | |||
LV2_MIDI_MSG_RESET = 0xFF /**< Reset */ | |||
} LV2_Midi_Message_Type; | |||
/** | |||
Standard MIDI Controller Numbers. | |||
*/ | |||
typedef enum { | |||
LV2_MIDI_CTL_MSB_BANK = 0x00, /**< Bank Selection */ | |||
LV2_MIDI_CTL_MSB_MODWHEEL = 0x01, /**< Modulation */ | |||
LV2_MIDI_CTL_MSB_BREATH = 0x02, /**< Breath */ | |||
LV2_MIDI_CTL_MSB_FOOT = 0x04, /**< Foot */ | |||
LV2_MIDI_CTL_MSB_PORTAMENTO_TIME = 0x05, /**< Portamento Time */ | |||
LV2_MIDI_CTL_MSB_DATA_ENTRY = 0x06, /**< Data Entry */ | |||
LV2_MIDI_CTL_MSB_MAIN_VOLUME = 0x07, /**< Main Volume */ | |||
LV2_MIDI_CTL_MSB_BALANCE = 0x08, /**< Balance */ | |||
LV2_MIDI_CTL_MSB_PAN = 0x0A, /**< Panpot */ | |||
LV2_MIDI_CTL_MSB_EXPRESSION = 0x0B, /**< Expression */ | |||
LV2_MIDI_CTL_MSB_EFFECT1 = 0x0C, /**< Effect1 */ | |||
LV2_MIDI_CTL_MSB_EFFECT2 = 0x0D, /**< Effect2 */ | |||
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE1 = 0x10, /**< General Purpose 1 */ | |||
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE2 = 0x11, /**< General Purpose 2 */ | |||
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE3 = 0x12, /**< General Purpose 3 */ | |||
LV2_MIDI_CTL_MSB_GENERAL_PURPOSE4 = 0x13, /**< General Purpose 4 */ | |||
LV2_MIDI_CTL_LSB_BANK = 0x20, /**< Bank Selection */ | |||
LV2_MIDI_CTL_LSB_MODWHEEL = 0x21, /**< Modulation */ | |||
LV2_MIDI_CTL_LSB_BREATH = 0x22, /**< Breath */ | |||
LV2_MIDI_CTL_LSB_FOOT = 0x24, /**< Foot */ | |||
LV2_MIDI_CTL_LSB_PORTAMENTO_TIME = 0x25, /**< Portamento Time */ | |||
LV2_MIDI_CTL_LSB_DATA_ENTRY = 0x26, /**< Data Entry */ | |||
LV2_MIDI_CTL_LSB_MAIN_VOLUME = 0x27, /**< Main Volume */ | |||
LV2_MIDI_CTL_LSB_BALANCE = 0x28, /**< Balance */ | |||
LV2_MIDI_CTL_LSB_PAN = 0x2A, /**< Panpot */ | |||
LV2_MIDI_CTL_LSB_EXPRESSION = 0x2B, /**< Expression */ | |||
LV2_MIDI_CTL_LSB_EFFECT1 = 0x2C, /**< Effect1 */ | |||
LV2_MIDI_CTL_LSB_EFFECT2 = 0x2D, /**< Effect2 */ | |||
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE1 = 0x30, /**< General Purpose 1 */ | |||
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE2 = 0x31, /**< General Purpose 2 */ | |||
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE3 = 0x32, /**< General Purpose 3 */ | |||
LV2_MIDI_CTL_LSB_GENERAL_PURPOSE4 = 0x33, /**< General Purpose 4 */ | |||
LV2_MIDI_CTL_SUSTAIN = 0x40, /**< Sustain Pedal */ | |||
LV2_MIDI_CTL_PORTAMENTO = 0x41, /**< Portamento */ | |||
LV2_MIDI_CTL_SOSTENUTO = 0x42, /**< Sostenuto */ | |||
LV2_MIDI_CTL_SOFT_PEDAL = 0x43, /**< Soft Pedal */ | |||
LV2_MIDI_CTL_LEGATO_FOOTSWITCH = 0x44, /**< Legato Foot Switch */ | |||
LV2_MIDI_CTL_HOLD2 = 0x45, /**< Hold2 */ | |||
LV2_MIDI_CTL_SC1_SOUND_VARIATION = 0x46, /**< SC1 Sound Variation */ | |||
LV2_MIDI_CTL_SC2_TIMBRE = 0x47, /**< SC2 Timbre */ | |||
LV2_MIDI_CTL_SC3_RELEASE_TIME = 0x48, /**< SC3 Release Time */ | |||
LV2_MIDI_CTL_SC4_ATTACK_TIME = 0x49, /**< SC4 Attack Time */ | |||
LV2_MIDI_CTL_SC5_BRIGHTNESS = 0x4A, /**< SC5 Brightness */ | |||
LV2_MIDI_CTL_SC6 = 0x4B, /**< SC6 */ | |||
LV2_MIDI_CTL_SC7 = 0x4C, /**< SC7 */ | |||
LV2_MIDI_CTL_SC8 = 0x4D, /**< SC8 */ | |||
LV2_MIDI_CTL_SC9 = 0x4E, /**< SC9 */ | |||
LV2_MIDI_CTL_SC10 = 0x4F, /**< SC10 */ | |||
LV2_MIDI_CTL_GENERAL_PURPOSE5 = 0x50, /**< General Purpose 5 */ | |||
LV2_MIDI_CTL_GENERAL_PURPOSE6 = 0x51, /**< General Purpose 6 */ | |||
LV2_MIDI_CTL_GENERAL_PURPOSE7 = 0x52, /**< General Purpose 7 */ | |||
LV2_MIDI_CTL_GENERAL_PURPOSE8 = 0x53, /**< General Purpose 8 */ | |||
LV2_MIDI_CTL_PORTAMENTO_CONTROL = 0x54, /**< Portamento Control */ | |||
LV2_MIDI_CTL_E1_REVERB_DEPTH = 0x5B, /**< E1 Reverb Depth */ | |||
LV2_MIDI_CTL_E2_TREMOLO_DEPTH = 0x5C, /**< E2 Tremolo Depth */ | |||
LV2_MIDI_CTL_E3_CHORUS_DEPTH = 0x5D, /**< E3 Chorus Depth */ | |||
LV2_MIDI_CTL_E4_DETUNE_DEPTH = 0x5E, /**< E4 Detune Depth */ | |||
LV2_MIDI_CTL_E5_PHASER_DEPTH = 0x5F, /**< E5 Phaser Depth */ | |||
LV2_MIDI_CTL_DATA_INCREMENT = 0x60, /**< Data Increment */ | |||
LV2_MIDI_CTL_DATA_DECREMENT = 0x61, /**< Data Decrement */ | |||
LV2_MIDI_CTL_NRPN_LSB = 0x62, /**< Non-registered Parameter Number */ | |||
LV2_MIDI_CTL_NRPN_MSB = 0x63, /**< Non-registered Parameter Number */ | |||
LV2_MIDI_CTL_RPN_LSB = 0x64, /**< Registered Parameter Number */ | |||
LV2_MIDI_CTL_RPN_MSB = 0x65, /**< Registered Parameter Number */ | |||
LV2_MIDI_CTL_ALL_SOUNDS_OFF = 0x78, /**< All Sounds Off */ | |||
LV2_MIDI_CTL_RESET_CONTROLLERS = 0x79, /**< Reset Controllers */ | |||
LV2_MIDI_CTL_LOCAL_CONTROL_SWITCH = 0x7A, /**< Local Control Switch */ | |||
LV2_MIDI_CTL_ALL_NOTES_OFF = 0x7B, /**< All Notes Off */ | |||
LV2_MIDI_CTL_OMNI_OFF = 0x7C, /**< Omni Off */ | |||
LV2_MIDI_CTL_OMNI_ON = 0x7D, /**< Omni On */ | |||
LV2_MIDI_CTL_MONO1 = 0x7E, /**< Mono1 */ | |||
LV2_MIDI_CTL_MONO2 = 0x7F /**< Mono2 */ | |||
} LV2_Midi_Controller; | |||
/** | |||
Return true iff @p msg is a MIDI voice message (which has a channel). | |||
*/ | |||
static inline bool | |||
lv2_midi_is_voice_message(const uint8_t* msg) { | |||
return msg[0] >= 0x80 && msg[0] < 0xF0; | |||
} | |||
/** | |||
Return true iff @p msg is a MIDI system message (which has no channel). | |||
*/ | |||
static inline bool | |||
lv2_midi_is_system_message(const uint8_t* msg) { | |||
switch (msg[0]) { | |||
case 0xF4: case 0xF5: case 0xF7: case 0xF9: case 0xFD: | |||
return false; | |||
default: | |||
return (msg[0] & 0xF0) == 0xF0; | |||
} | |||
} | |||
/** | |||
Return the type of a MIDI message. | |||
@param msg Pointer to the start (status byte) of a MIDI message. | |||
*/ | |||
static inline LV2_Midi_Message_Type | |||
lv2_midi_message_type(const uint8_t* msg) { | |||
if (lv2_midi_is_voice_message(msg)) { | |||
return (LV2_Midi_Message_Type)(msg[0] & 0xF0); | |||
} else if (lv2_midi_is_system_message(msg)) { | |||
return (LV2_Midi_Message_Type)msg[0]; | |||
} else { | |||
return LV2_MIDI_MSG_INVALID; | |||
} | |||
} | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_MIDI_H */ |
@@ -0,0 +1,34 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_MORPH_H | |||
#define LV2_MORPH_H | |||
#include <stdint.h> | |||
#include "lv2/lv2plug.in/ns/lv2core/lv2.h" | |||
#include "lv2/lv2plug.in/ns/ext/urid/urid.h" | |||
#define LV2_MORPH_URI "http://lv2plug.in/ns/ext/morph" | |||
#define LV2_MORPH_PREFIX LV2_MORPH_URI "#" | |||
#define LV2_MORPH__AutoMorphPort LV2_MORPH_PREFIX "AutoMorphPort" | |||
#define LV2_MORPH__MorphPort LV2_MORPH_PREFIX "MorphPort" | |||
#define LV2_MORPH__interface LV2_MORPH_PREFIX "interface" | |||
#define LV2_MORPH__supportsType LV2_MORPH_PREFIX "supportsType" | |||
#define LV2_MORPH__currentType LV2_MORPH_PREFIX "currentType" | |||
#endif /* LV2_MORPH_H */ |
@@ -0,0 +1,132 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_OPTIONS_H | |||
#define LV2_OPTIONS_H | |||
#include <stdint.h> | |||
#include "urid.h" | |||
#include "lv2.h" | |||
#define LV2_OPTIONS_URI "http://lv2plug.in/ns/ext/options" | |||
#define LV2_OPTIONS_PREFIX LV2_OPTIONS_URI "#" | |||
#define LV2_OPTIONS__Option LV2_OPTIONS_PREFIX "Option" | |||
#define LV2_OPTIONS__interface LV2_OPTIONS_PREFIX "interface" | |||
#define LV2_OPTIONS__options LV2_OPTIONS_PREFIX "options" | |||
#define LV2_OPTIONS__requiredOption LV2_OPTIONS_PREFIX "requiredOption" | |||
#define LV2_OPTIONS__supportedOption LV2_OPTIONS_PREFIX "supportedOption" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
The context of an Option, which defines the subject it applies to. | |||
*/ | |||
typedef enum { | |||
/** | |||
This option applies to the instance itself. The subject must be | |||
ignored. | |||
*/ | |||
LV2_OPTIONS_INSTANCE, | |||
/** | |||
This option applies to some named resource. The subject is a URI mapped | |||
to an integer (a LV2_URID, like the key) | |||
*/ | |||
LV2_OPTIONS_RESOURCE, | |||
/** | |||
This option applies to some blank node. The subject is a blank node | |||
identifier, which is valid only within the current local scope. | |||
*/ | |||
LV2_OPTIONS_BLANK, | |||
/** | |||
This option applies to a port on the instance. The subject is the | |||
port's index. | |||
*/ | |||
LV2_OPTIONS_PORT | |||
} LV2_Options_Context; | |||
/** | |||
An option. | |||
This is a property with a subject, also known as a triple or statement. | |||
This struct is useful anywhere a statement needs to be passed where no | |||
memory ownership issues are present (since the value is a const pointer). | |||
Options can be passed to an instance via the feature LV2_OPTIONS__options | |||
with data pointed to an array of options terminated by a zeroed option, or | |||
accessed/manipulated using LV2_Options_Interface. | |||
*/ | |||
typedef struct _LV2_Options_Option { | |||
LV2_Options_Context context; /**< Context (type of subject). */ | |||
uint32_t subject; /**< Subject. */ | |||
LV2_URID key; /**< Key (property). */ | |||
uint32_t size; /**< Size of value in bytes. */ | |||
LV2_URID type; /**< Type of value (datatype). */ | |||
const void* value; /**< Pointer to value (object). */ | |||
} LV2_Options_Option; | |||
/** A status code for option functions. */ | |||
typedef enum { | |||
LV2_OPTIONS_SUCCESS = 0, /**< Completed successfully. */ | |||
LV2_OPTIONS_ERR_UNKNOWN = 1, /**< Unknown error. */ | |||
LV2_OPTIONS_ERR_BAD_SUBJECT = 1 << 1, /**< Invalid/unsupported subject. */ | |||
LV2_OPTIONS_ERR_BAD_KEY = 1 << 2, /**< Invalid/unsupported key. */ | |||
LV2_OPTIONS_ERR_BAD_VALUE = 1 << 3 /**< Invalid/unsupported value. */ | |||
} LV2_Options_Status; | |||
/** | |||
Interface for dynamically setting options (LV2_OPTIONS__interface). | |||
*/ | |||
typedef struct _LV2_Options_Interface { | |||
/** | |||
Get the given options. | |||
Each element of the passed options array MUST have type, subject, and | |||
key set. All other fields (size, type, value) MUST be initialised to | |||
zero, and are set to the option value if such an option is found. | |||
This function is in the "instantiation" LV2 threading class, so no other | |||
instance functions may be called concurrently. | |||
@return Bitwise OR of LV2_Options_Status values. | |||
*/ | |||
uint32_t (*get)(LV2_Handle instance, | |||
LV2_Options_Option* options); | |||
/** | |||
Set the given options. | |||
This function is in the "instantiation" LV2 threading class, so no other | |||
instance functions may be called concurrently. | |||
@return Bitwise OR of LV2_Options_Status values. | |||
*/ | |||
uint32_t (*set)(LV2_Handle instance, | |||
const LV2_Options_Option* options); | |||
} LV2_Options_Interface; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_OPTIONS_H */ |
@@ -0,0 +1,49 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_PARAMETERS_H | |||
#define LV2_PARAMETERS_H | |||
#define LV2_PARAMETERS_URI "http://lv2plug.in/ns/ext/parameters" | |||
#define LV2_PARAMETERS_PREFIX LV2_PARAMETERS_URI "#" | |||
#define LV2_PARAMETERS__CompressorControls LV2_PARAMETERS_PREFIX "CompressorControls" | |||
#define LV2_PARAMETERS__ControlGroup LV2_PARAMETERS_PREFIX "ControlGroup" | |||
#define LV2_PARAMETERS__EnvelopeControls LV2_PARAMETERS_PREFIX "EnvelopeControls" | |||
#define LV2_PARAMETERS__FilterControls LV2_PARAMETERS_PREFIX "FilterControls" | |||
#define LV2_PARAMETERS__OscillatorControls LV2_PARAMETERS_PREFIX "OscillatorControls" | |||
#define LV2_PARAMETERS__amplitude LV2_PARAMETERS_PREFIX "amplitude" | |||
#define LV2_PARAMETERS__attack LV2_PARAMETERS_PREFIX "attack" | |||
#define LV2_PARAMETERS__bypass LV2_PARAMETERS_PREFIX "bypass" | |||
#define LV2_PARAMETERS__cutoffFrequency LV2_PARAMETERS_PREFIX "cutoffFrequency" | |||
#define LV2_PARAMETERS__decay LV2_PARAMETERS_PREFIX "decay" | |||
#define LV2_PARAMETERS__delay LV2_PARAMETERS_PREFIX "delay" | |||
#define LV2_PARAMETERS__dryLevel LV2_PARAMETERS_PREFIX "dryLevel" | |||
#define LV2_PARAMETERS__frequency LV2_PARAMETERS_PREFIX "frequency" | |||
#define LV2_PARAMETERS__gain LV2_PARAMETERS_PREFIX "gain" | |||
#define LV2_PARAMETERS__hold LV2_PARAMETERS_PREFIX "hold" | |||
#define LV2_PARAMETERS__pulseWidth LV2_PARAMETERS_PREFIX "pulseWidth" | |||
#define LV2_PARAMETERS__ratio LV2_PARAMETERS_PREFIX "ratio" | |||
#define LV2_PARAMETERS__release LV2_PARAMETERS_PREFIX "release" | |||
#define LV2_PARAMETERS__resonance LV2_PARAMETERS_PREFIX "resonance" | |||
#define LV2_PARAMETERS__sampleRate LV2_PARAMETERS_PREFIX "sampleRate" | |||
#define LV2_PARAMETERS__sustain LV2_PARAMETERS_PREFIX "sustain" | |||
#define LV2_PARAMETERS__threshold LV2_PARAMETERS_PREFIX "threshold" | |||
#define LV2_PARAMETERS__waveform LV2_PARAMETERS_PREFIX "waveform" | |||
#define LV2_PARAMETERS__wetDryRatio LV2_PARAMETERS_PREFIX "wetDryRatio" | |||
#define LV2_PARAMETERS__wetLevel LV2_PARAMETERS_PREFIX "wetLevel" | |||
#endif /* LV2_PARAMETERS_H */ |
@@ -0,0 +1,55 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file patch.h C header for the LV2 Patch extension | |||
<http://lv2plug.in/ns/ext/patch>. | |||
The patch extension is purely data, this header merely defines URIs | |||
for convenience. | |||
*/ | |||
#ifndef LV2_PATCH_H | |||
#define LV2_PATCH_H | |||
#define LV2_PATCH_URI "http://lv2plug.in/ns/ext/patch" | |||
#define LV2_PATCH_PREFIX LV2_PATCH_URI "#" | |||
#define LV2_PATCH__Ack LV2_PATCH_PREFIX "Ack" | |||
#define LV2_PATCH__Delete LV2_PATCH_PREFIX "Delete" | |||
#define LV2_PATCH__Error LV2_PATCH_PREFIX "Error" | |||
#define LV2_PATCH__Get LV2_PATCH_PREFIX "Get" | |||
#define LV2_PATCH__Message LV2_PATCH_PREFIX "Message" | |||
#define LV2_PATCH__Move LV2_PATCH_PREFIX "Move" | |||
#define LV2_PATCH__Patch LV2_PATCH_PREFIX "Patch" | |||
#define LV2_PATCH__Post LV2_PATCH_PREFIX "Post" | |||
#define LV2_PATCH__Put LV2_PATCH_PREFIX "Put" | |||
#define LV2_PATCH__Request LV2_PATCH_PREFIX "Request" | |||
#define LV2_PATCH__Response LV2_PATCH_PREFIX "Response" | |||
#define LV2_PATCH__Set LV2_PATCH_PREFIX "Set" | |||
#define LV2_PATCH__add LV2_PATCH_PREFIX "add" | |||
#define LV2_PATCH__body LV2_PATCH_PREFIX "body" | |||
#define LV2_PATCH__destination LV2_PATCH_PREFIX "destination" | |||
#define LV2_PATCH__property LV2_PATCH_PREFIX "property" | |||
#define LV2_PATCH__readable LV2_PATCH_PREFIX "readable" | |||
#define LV2_PATCH__remove LV2_PATCH_PREFIX "remove" | |||
#define LV2_PATCH__request LV2_PATCH_PREFIX "request" | |||
#define LV2_PATCH__subject LV2_PATCH_PREFIX "subject" | |||
#define LV2_PATCH__value LV2_PATCH_PREFIX "value" | |||
#define LV2_PATCH__wildcard LV2_PATCH_PREFIX "wildcard" | |||
#define LV2_PATCH__writable LV2_PATCH_PREFIX "writable" | |||
#endif /* LV2_PATCH_H */ |
@@ -0,0 +1,64 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file port-groups.h | |||
C definitions for the LV2 Port Groups extension | |||
<http://lv2plug.in/ns/ext/port-groups>. | |||
*/ | |||
#ifndef LV2_PORT_GROUPS_H | |||
#define LV2_PORT_GROUPS_H | |||
#define LV2_PORT_GROUPS_URI "http://lv2plug.in/ns/ext/port-groups" | |||
#define LV2_PORT_GROUPS_PREFIX LV2_PORT_GROUPS_URI "#" | |||
#define LV2_PORT_GROUPS__DiscreteGroup LV2_PORT_GROUPS_PREFIX "DiscreteGroup" | |||
#define LV2_PORT_GROUPS__Element LV2_PORT_GROUPS_PREFIX "Element" | |||
#define LV2_PORT_GROUPS__FivePointOneGroup LV2_PORT_GROUPS_PREFIX "FivePointOneGroup" | |||
#define LV2_PORT_GROUPS__FivePointZeroGroup LV2_PORT_GROUPS_PREFIX "FivePointZeroGroup" | |||
#define LV2_PORT_GROUPS__FourPointZeroGroup LV2_PORT_GROUPS_PREFIX "FourPointZeroGroup" | |||
#define LV2_PORT_GROUPS__Group LV2_PORT_GROUPS_PREFIX "Group" | |||
#define LV2_PORT_GROUPS__InputGroup LV2_PORT_GROUPS_PREFIX "InputGroup" | |||
#define LV2_PORT_GROUPS__MidSideGroup LV2_PORT_GROUPS_PREFIX "MidSideGroup" | |||
#define LV2_PORT_GROUPS__MonoGroup LV2_PORT_GROUPS_PREFIX "MonoGroup" | |||
#define LV2_PORT_GROUPS__OutputGroup LV2_PORT_GROUPS_PREFIX "OutputGroup" | |||
#define LV2_PORT_GROUPS__SevenPointOneGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneGroup" | |||
#define LV2_PORT_GROUPS__SevenPointOneWideGroup LV2_PORT_GROUPS_PREFIX "SevenPointOneWideGroup" | |||
#define LV2_PORT_GROUPS__SixPointOneGroup LV2_PORT_GROUPS_PREFIX "SixPointOneGroup" | |||
#define LV2_PORT_GROUPS__StereoGroup LV2_PORT_GROUPS_PREFIX "StereoGroup" | |||
#define LV2_PORT_GROUPS__ThreePointZeroGroup LV2_PORT_GROUPS_PREFIX "ThreePointZeroGroup" | |||
#define LV2_PORT_GROUPS__center LV2_PORT_GROUPS_PREFIX "center" | |||
#define LV2_PORT_GROUPS__centerLeft LV2_PORT_GROUPS_PREFIX "centerLeft" | |||
#define LV2_PORT_GROUPS__centerRight LV2_PORT_GROUPS_PREFIX "centerRight" | |||
#define LV2_PORT_GROUPS__element LV2_PORT_GROUPS_PREFIX "element" | |||
#define LV2_PORT_GROUPS__group LV2_PORT_GROUPS_PREFIX "group" | |||
#define LV2_PORT_GROUPS__left LV2_PORT_GROUPS_PREFIX "left" | |||
#define LV2_PORT_GROUPS__lowFrequencyEffects LV2_PORT_GROUPS_PREFIX "lowFrequencyEffects" | |||
#define LV2_PORT_GROUPS__mainInput LV2_PORT_GROUPS_PREFIX "mainInput" | |||
#define LV2_PORT_GROUPS__mainOutput LV2_PORT_GROUPS_PREFIX "mainOutput" | |||
#define LV2_PORT_GROUPS__rearCenter LV2_PORT_GROUPS_PREFIX "rearCenter" | |||
#define LV2_PORT_GROUPS__rearLeft LV2_PORT_GROUPS_PREFIX "rearLeft" | |||
#define LV2_PORT_GROUPS__rearRight LV2_PORT_GROUPS_PREFIX "rearRight" | |||
#define LV2_PORT_GROUPS__right LV2_PORT_GROUPS_PREFIX "right" | |||
#define LV2_PORT_GROUPS__side LV2_PORT_GROUPS_PREFIX "side" | |||
#define LV2_PORT_GROUPS__sideChainOf LV2_PORT_GROUPS_PREFIX "sideChainOf" | |||
#define LV2_PORT_GROUPS__sideLeft LV2_PORT_GROUPS_PREFIX "sideLeft" | |||
#define LV2_PORT_GROUPS__sideRight LV2_PORT_GROUPS_PREFIX "sideRight" | |||
#define LV2_PORT_GROUPS__source LV2_PORT_GROUPS_PREFIX "source" | |||
#define LV2_PORT_GROUPS__subGroupOf LV2_PORT_GROUPS_PREFIX "subGroupOf" | |||
#endif /* LV2_PORT_GROUPS_H */ |
@@ -0,0 +1,42 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file port-props.h | |||
C definitions for the LV2 Port Props extension | |||
<http://lv2plug.in/ns/ext/port-props>. | |||
*/ | |||
#ifndef LV2_PORT_PROPS_H | |||
#define LV2_PORT_PROPS_H | |||
#define LV2_PORT_PROPS_URI "http://lv2plug.in/ns/ext/port-props" | |||
#define LV2_PORT_PROPS_PREFIX LV2_PORT_PROPS_URI "#" | |||
#define LV2_PORT_PROPS__causesArtifacts LV2_PORT_PROPS_PREFIX "causesArtifacts" | |||
#define LV2_PORT_PROPS__continuousCV LV2_PORT_PROPS_PREFIX "continuousCV" | |||
#define LV2_PORT_PROPS__discreteCV LV2_PORT_PROPS_PREFIX "discreteCV" | |||
#define LV2_PORT_PROPS__displayPriority LV2_PORT_PROPS_PREFIX "displayPriority" | |||
#define LV2_PORT_PROPS__expensive LV2_PORT_PROPS_PREFIX "expensive" | |||
#define LV2_PORT_PROPS__hasStrictBounds LV2_PORT_PROPS_PREFIX "hasStrictBounds" | |||
#define LV2_PORT_PROPS__logarithmic LV2_PORT_PROPS_PREFIX "logarithmic" | |||
#define LV2_PORT_PROPS__notAutomatic LV2_PORT_PROPS_PREFIX "notAutomatic" | |||
#define LV2_PORT_PROPS__notOnGUI LV2_PORT_PROPS_PREFIX "notOnGUI" | |||
#define LV2_PORT_PROPS__rangeSteps LV2_PORT_PROPS_PREFIX "rangeSteps" | |||
#define LV2_PORT_PROPS__supportsStrictBounds LV2_PORT_PROPS_PREFIX "supportsStrictBounds" | |||
#define LV2_PORT_PROPS__trigger LV2_PORT_PROPS_PREFIX "trigger" | |||
#endif /* LV2_PORT_PROPS_H */ |
@@ -0,0 +1,34 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file presets.h | |||
C definitions for the LV2 Presets extension | |||
<http://lv2plug.in/ns/ext/presets>. | |||
*/ | |||
#ifndef LV2_PRESETS_H | |||
#define LV2_PRESETS_H | |||
#define LV2_PRESETS_URI "http://lv2plug.in/ns/ext/presets" | |||
#define LV2_PRESETS_PREFIX LV2_PRESETS_URI "#" | |||
#define LV2_PRESETS__Preset LV2_PRESETS_PREFIX "Preset" | |||
#define LV2_PRESETS__preset LV2_PRESETS_PREFIX "preset" | |||
#define LV2_PRESETS__value LV2_PRESETS_PREFIX "value" | |||
#endif /* LV2_PRESETS_H */ |
@@ -0,0 +1,72 @@ | |||
/* | |||
Copyright 2007-2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
#ifndef LV2_RESIZE_PORT_H | |||
#define LV2_RESIZE_PORT_H | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#define LV2_RESIZE_PORT_URI "http://lv2plug.in/ns/ext/resize-port" | |||
#define LV2_RESIZE_PORT_PREFIX LV2_RESIZE_PORT_URI "#" | |||
#define LV2_RESIZE_PORT__asLargeAs LV2_RESIZE_PORT_PREFIX "asLargeAs" | |||
#define LV2_RESIZE_PORT__minimumSize LV2_RESIZE_PORT_PREFIX "minimumSize" | |||
#define LV2_RESIZE_PORT__resize LV2_RESIZE_PORT_PREFIX "resize" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** A status code for state functions. */ | |||
typedef enum { | |||
LV2_RESIZE_PORT_SUCCESS = 0, /**< Completed successfully. */ | |||
LV2_RESIZE_PORT_ERR_UNKNOWN = 1, /**< Unknown error. */ | |||
LV2_RESIZE_PORT_ERR_NO_SPACE = 2 /**< Insufficient space. */ | |||
} LV2_Resize_Port_Status; | |||
typedef void* LV2_Resize_Port_Feature_Data; | |||
typedef struct { | |||
LV2_Resize_Port_Feature_Data data; | |||
/** | |||
Resize a port buffer to at least @a size bytes. | |||
This function MAY return an error, in which case the port buffer was not | |||
resized and the port is still connected to the same location. Plugins | |||
MUST gracefully handle this situation. | |||
This function is in the audio threading class. | |||
The host MUST preserve the contents of the port buffer when resizing. | |||
Plugins MAY resize a port many times in a single run callback. Hosts | |||
SHOULD make this as inexpensive as possible. | |||
*/ | |||
LV2_Resize_Port_Status (*resize)(LV2_Resize_Port_Feature_Data data, | |||
uint32_t index, | |||
size_t size); | |||
} LV2_Resize_Port_Resize; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_RESIZE_PORT_H */ | |||
@@ -0,0 +1,352 @@ | |||
/* | |||
Copyright 2010-2012 David Robillard <http://drobilla.net> | |||
Copyright 2010 Leonard Ritter <paniq@paniq.org> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file state.h | |||
C API for the LV2 State extension <http://lv2plug.in/ns/ext/state>. | |||
*/ | |||
#ifndef LV2_STATE_H | |||
#define LV2_STATE_H | |||
#include <stddef.h> | |||
#include <stdint.h> | |||
#include "lv2.h" | |||
#define LV2_STATE_URI "http://lv2plug.in/ns/ext/state" | |||
#define LV2_STATE_PREFIX LV2_STATE_URI "#" | |||
#define LV2_STATE__State LV2_STATE_PREFIX "State" | |||
#define LV2_STATE__interface LV2_STATE_PREFIX "interface" | |||
#define LV2_STATE__loadDefaultState LV2_STATE_PREFIX "loadDefaultState" | |||
#define LV2_STATE__makePath LV2_STATE_PREFIX "makePath" | |||
#define LV2_STATE__mapPath LV2_STATE_PREFIX "mapPath" | |||
#define LV2_STATE__state LV2_STATE_PREFIX "state" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
typedef void* LV2_State_Handle; | |||
typedef void* LV2_State_Map_Path_Handle; | |||
typedef void* LV2_State_Make_Path_Handle; | |||
/** | |||
Flags describing value characteristics. | |||
These flags are used along with the value's type URI to determine how to | |||
(de-)serialise the value data, or whether it is even possible to do so. | |||
*/ | |||
typedef enum { | |||
/** | |||
Plain Old Data. | |||
Values with this flag contain no pointers or references to other areas | |||
of memory. It is safe to copy POD values with a simple memcpy and store | |||
them for the duration of the process. A POD value is not necessarily | |||
safe to trasmit between processes or machines (e.g. filenames are POD), | |||
see LV2_STATE_IS_PORTABLE for details. | |||
Implementations MUST NOT attempt to copy or serialise a non-POD value if | |||
they do not understand its type (and thus know how to correctly do so). | |||
*/ | |||
LV2_STATE_IS_POD = 1, | |||
/** | |||
Portable (architecture independent) data. | |||
Values with this flag are in a format that is usable on any | |||
architecture. A portable value saved on one machine can be restored on | |||
another machine regardless of architecture. The format of portable | |||
values MUST NOT depend on architecture-specific properties like | |||
endianness or alignment. Portable values MUST NOT contain filenames. | |||
*/ | |||
LV2_STATE_IS_PORTABLE = 1 << 1, | |||
/** | |||
Native data. | |||
This flag is used by the host to indicate that the saved data is only | |||
going to be used locally in the currently running process (e.g. for | |||
instance duplication or snapshots), so the plugin should use the most | |||
efficient representation possible and not worry about serialisation | |||
and portability. | |||
*/ | |||
LV2_STATE_IS_NATIVE = 1 << 2 | |||
} LV2_State_Flags; | |||
/** A status code for state functions. */ | |||
typedef enum { | |||
LV2_STATE_SUCCESS = 0, /**< Completed successfully. */ | |||
LV2_STATE_ERR_UNKNOWN = 1, /**< Unknown error. */ | |||
LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ | |||
LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ | |||
LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ | |||
LV2_STATE_ERR_NO_PROPERTY = 5 /**< Failed due to missing property. */ | |||
} LV2_State_Status; | |||
/** | |||
A host-provided function to store a property. | |||
@param handle Must be the handle passed to LV2_State_Interface.save(). | |||
@param key The key to store @p value under (URID). | |||
@param value Pointer to the value to be stored. | |||
@param size The size of @p value in bytes. | |||
@param type The type of @p value (URID). | |||
@param flags LV2_State_Flags for @p value. | |||
@return 0 on success, otherwise a non-zero error code. | |||
The host passes a callback of this type to LV2_State_Interface.save(). This | |||
callback is called repeatedly by the plugin to store all the properties that | |||
describe its current state. | |||
DO NOT INVENT NONSENSE URI SCHEMES FOR THE KEY. Best is to use keys from | |||
existing vocabularies. If nothing appropriate is available, use http URIs | |||
that point to somewhere you can host documents so documentation can be made | |||
resolvable (e.g. a child of the plugin or project URI). If this is not | |||
possible, invent a URN scheme, e.g. urn:myproj:whatever. The plugin MUST | |||
NOT pass an invalid URI key. | |||
The host MAY fail to store a property for whatever reason, but SHOULD | |||
store any property that is LV2_STATE_IS_POD and LV2_STATE_IS_PORTABLE. | |||
Implementations SHOULD use the types from the LV2 Atom extension | |||
(http://lv2plug.in/ns/ext/atom) wherever possible. The plugin SHOULD | |||
attempt to fall-back and avoid the error if possible. | |||
Note that @p size MUST be > 0, and @p value MUST point to a valid region of | |||
memory @p size bytes long (this is required to make restore unambiguous). | |||
The plugin MUST NOT attempt to use this function outside of the | |||
LV2_State_Interface.restore() context. | |||
*/ | |||
typedef LV2_State_Status (*LV2_State_Store_Function)( | |||
LV2_State_Handle handle, | |||
uint32_t key, | |||
const void* value, | |||
size_t size, | |||
uint32_t type, | |||
uint32_t flags); | |||
/** | |||
A host-provided function to retrieve a property. | |||
@param handle Must be the handle passed to LV2_State_Interface.restore(). | |||
@param key The key of the property to retrieve (URID). | |||
@param size (Output) If non-NULL, set to the size of the restored value. | |||
@param type (Output) If non-NULL, set to the type of the restored value. | |||
@param flags (Output) If non-NULL, set to the flags for the restored value. | |||
@return A pointer to the restored value (object), or NULL if no value | |||
has been stored under @p key. | |||
A callback of this type is passed by the host to | |||
LV2_State_Interface.restore(). This callback is called repeatedly by the | |||
plugin to retrieve any properties it requires to restore its state. | |||
The returned value MUST remain valid until LV2_State_Interface.restore() | |||
returns. The plugin MUST NOT attempt to use this function, or any value | |||
returned from it, outside of the LV2_State_Interface.restore() context. | |||
*/ | |||
typedef const void* (*LV2_State_Retrieve_Function)( | |||
LV2_State_Handle handle, | |||
uint32_t key, | |||
size_t* size, | |||
uint32_t* type, | |||
uint32_t* flags); | |||
/** | |||
LV2 Plugin State Interface. | |||
When the plugin's extension_data is called with argument | |||
LV2_STATE__interface, the plugin MUST return an LV2_State_Interface | |||
structure, which remains valid for the lifetime of the plugin. | |||
The host can use the contained function pointers to save and restore the | |||
state of a plugin instance at any time, provided the threading restrictions | |||
of the functions are met. | |||
Stored data is only guaranteed to be compatible between instances of plugins | |||
with the same URI (i.e. if a change to a plugin would cause a fatal error | |||
when restoring state saved by a previous version of that plugin, the plugin | |||
URI MUST change just as it must when ports change incompatibly). Plugin | |||
authors should consider this possibility, and always store sensible data | |||
with meaningful types to avoid such problems in the future. | |||
*/ | |||
typedef struct _LV2_State_Interface { | |||
/** | |||
Save plugin state using a host-provided @p store callback. | |||
@param instance The instance handle of the plugin. | |||
@param store The host-provided store callback. | |||
@param handle An opaque pointer to host data which MUST be passed as the | |||
handle parameter to @p store if it is called. | |||
@param flags Flags describing desired properties of this save. These | |||
flags may be used to determine the most appropriate values to store. | |||
@param features Extensible parameter for passing any additional | |||
features to be used for this save. | |||
The plugin is expected to store everything necessary to completely | |||
restore its state later. Plugins SHOULD store simple POD data whenever | |||
possible, and consider the possibility of state being restored much | |||
later on a different machine. | |||
The @p handle pointer and @p store function MUST NOT be used | |||
beyond the scope of save(). | |||
This function has its own special threading class: it may not be called | |||
concurrently with any "Instantiation" function, but it may be called | |||
concurrently with functions in any other class, unless the definition of | |||
that class prohibits it (e.g. it may not be called concurrently with a | |||
"Discovery" function, but it may be called concurrently with an "Audio" | |||
function. The plugin is responsible for any locking or lock-free | |||
techniques necessary to make this possible. | |||
Note that in the simple case where state is only modified by restore(), | |||
there are no synchronization issues since save() is never called | |||
concurrently with restore() (though run() may read it during a save). | |||
Plugins that dynamically modify state while running, however, must take | |||
care to do so in such a way that a concurrent call to save() will save a | |||
consistent representation of plugin state for a single instant in time. | |||
*/ | |||
LV2_State_Status (*save)(LV2_Handle instance, | |||
LV2_State_Store_Function store, | |||
LV2_State_Handle handle, | |||
uint32_t flags, | |||
const LV2_Feature *const * features); | |||
/** | |||
Restore plugin state using a host-provided @p retrieve callback. | |||
@param instance The instance handle of the plugin. | |||
@param retrieve The host-provided retrieve callback. | |||
@param handle An opaque pointer to host data which MUST be passed as the | |||
handle parameter to @p retrieve if it is called. | |||
@param flags Currently unused. | |||
@param features Extensible parameter for passing any additional | |||
features to be used for this restore. | |||
The plugin MAY assume a restored value was set by a previous call to | |||
LV2_State_Interface.save() by a plugin with the same URI. | |||
The plugin MUST gracefully fall back to a default value when a value can | |||
not be retrieved. This allows the host to reset the plugin state with | |||
an empty map. | |||
The @p handle pointer and @p store function MUST NOT be used | |||
beyond the scope of restore(). | |||
This function is in the "Instantiation" threading class as defined by | |||
LV2. This means it MUST NOT be called concurrently with any other | |||
function on the same plugin instance. | |||
*/ | |||
LV2_State_Status (*restore)(LV2_Handle instance, | |||
LV2_State_Retrieve_Function retrieve, | |||
LV2_State_Handle handle, | |||
uint32_t flags, | |||
const LV2_Feature *const * features); | |||
} LV2_State_Interface; | |||
/** | |||
Feature data for state:mapPath (LV2_STATE__mapPath). | |||
*/ | |||
typedef struct { | |||
/** | |||
Opaque host data. | |||
*/ | |||
LV2_State_Map_Path_Handle handle; | |||
/** | |||
Map an absolute path to an abstract path for use in plugin state. | |||
@param handle MUST be the @p handle member of this struct. | |||
@param absolute_path The absolute path of a file. | |||
@return An abstract path suitable for use in plugin state. | |||
The plugin MUST use this function to map any paths that will be stored | |||
in plugin state. The returned value is an abstract path which MAY not | |||
be an actual file system path; @ref absolute_path() MUST be used to map | |||
it to an actual path in order to use the file. | |||
Plugins MUST NOT make any assumptions about abstract paths except that | |||
they can be mapped back to the absolute path of the "same" file (though | |||
not necessarily the same original path) using @ref absolute_path(). | |||
This function may only be called within the context of | |||
LV2_State_Interface methods. The caller is responsible for freeing the | |||
returned value with free(). | |||
*/ | |||
char* (*abstract_path)(LV2_State_Map_Path_Handle handle, | |||
const char* absolute_path); | |||
/** | |||
Map an abstract path from plugin state to an absolute path. | |||
@param handle MUST be the @p handle member of this struct. | |||
@param abstract_path An abstract path (e.g. a path from plugin state). | |||
@return An absolute file system path. | |||
The plugin MUST use this function in order to actually open or otherwise | |||
use any paths loaded from plugin state. | |||
This function may only be called within the context of | |||
LV2_State_Interface methods. The caller is responsible for freeing the | |||
returned value with free(). | |||
*/ | |||
char* (*absolute_path)(LV2_State_Map_Path_Handle handle, | |||
const char* abstract_path); | |||
} LV2_State_Map_Path; | |||
/** | |||
Feature data for state:makePath (@ref LV2_STATE__makePath). | |||
*/ | |||
typedef struct { | |||
/** | |||
Opaque host data. | |||
*/ | |||
LV2_State_Make_Path_Handle handle; | |||
/** | |||
Return a path the plugin may use to create a new file. | |||
@param handle MUST be the @p handle member of this struct. | |||
@param path The path of the new file within a namespace unique to this | |||
plugin instance. | |||
@return The absolute path to use for the new file. | |||
This function can be used by plugins to create files and directories, | |||
either at state saving time (if this feature is passed to | |||
LV2_State_Interface.save()) or any time (if this feature is passed to | |||
LV2_Descriptor.instantiate()). | |||
The host MUST do whatever is necessary for the plugin to be able to | |||
create a file at the returned path (e.g. using fopen), including | |||
creating any leading directories. | |||
If this function is passed to LV2_Descriptor.instantiate(), it may be | |||
called from any non-realtime context. If it is passed to | |||
LV2_State_Interface.save(), it may only be called within the dynamic | |||
scope of that function call. | |||
The caller is responsible for freeing the returned value with free(). | |||
*/ | |||
char* (*path)(LV2_State_Make_Path_Handle handle, | |||
const char* path); | |||
} LV2_State_Make_Path; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_STATE_H */ |
@@ -0,0 +1,49 @@ | |||
/* | |||
Copyright 2011 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file time.h C header for the LV2 Time extension | |||
<http://lv2plug.in/ns/ext/time>. | |||
*/ | |||
#ifndef LV2_TIME_H | |||
#define LV2_TIME_H | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#define LV2_TIME_URI "http://lv2plug.in/ns/ext/time" | |||
#define LV2_TIME__Time LV2_TIME_URI "#Time" | |||
#define LV2_TIME__Position LV2_TIME_URI "#Position" | |||
#define LV2_TIME__Rate LV2_TIME_URI "#Rate" | |||
#define LV2_TIME__position LV2_TIME_URI "#position" | |||
#define LV2_TIME__barBeat LV2_TIME_URI "#barBeat" | |||
#define LV2_TIME__bar LV2_TIME_URI "#bar" | |||
#define LV2_TIME__beat LV2_TIME_URI "#beat" | |||
#define LV2_TIME__beatUnit LV2_TIME_URI "#beatUnit" | |||
#define LV2_TIME__beatsPerBar LV2_TIME_URI "#beatsPerBar" | |||
#define LV2_TIME__beatsPerMinute LV2_TIME_URI "#beatsPerMinute" | |||
#define LV2_TIME__frame LV2_TIME_URI "#frame" | |||
#define LV2_TIME__framesPerSecond LV2_TIME_URI "#framesPerSecond" | |||
#define LV2_TIME__speed LV2_TIME_URI "#speed" | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_TIME_H */ |
@@ -0,0 +1,407 @@ | |||
/* | |||
LV2 UI Extension | |||
Copyright 2009-2012 David Robillard <d@drobilla.net> | |||
Copyright 2006-2011 Lars Luthman <lars.luthman@gmail.com> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file ui.h | |||
C header for the LV2 UI extension <http://lv2plug.in/ns/extensions/ui>. | |||
*/ | |||
#ifndef LV2_UI_H | |||
#define LV2_UI_H | |||
#include <stdint.h> | |||
#include "lv2.h" | |||
#define LV2_UI_URI "http://lv2plug.in/ns/extensions/ui" | |||
#define LV2_UI_PREFIX LV2_UI_URI "#" | |||
#define LV2_UI__CocoaUI LV2_UI_PREFIX "CocoaUI" | |||
#define LV2_UI__Gtk3UI LV2_UI_PREFIX "Gtk3UI" | |||
#define LV2_UI__GtkUI LV2_UI_PREFIX "GtkUI" | |||
#define LV2_UI__PortNotification LV2_UI_PREFIX "PortNotification" | |||
#define LV2_UI__Qt4UI LV2_UI_PREFIX "Qt4UI" | |||
#define LV2_UI__UI LV2_UI_PREFIX "UI" | |||
#define LV2_UI__WindowsUI LV2_UI_PREFIX "WindowsUI" | |||
#define LV2_UI__X11UI LV2_UI_PREFIX "X11UI" | |||
#define LV2_UI__binary LV2_UI_PREFIX "binary" | |||
#define LV2_UI__fixedSize LV2_UI_PREFIX "fixedSize" | |||
#define LV2_UI__idleInterface LV2_UI_PREFIX "idleInterface" | |||
#define LV2_UI__noUserResize LV2_UI_PREFIX "noUserResize" | |||
#define LV2_UI__notifyType LV2_UI_PREFIX "notifyType" | |||
#define LV2_UI__parent LV2_UI_PREFIX "parent" | |||
#define LV2_UI__plugin LV2_UI_PREFIX "plugin" | |||
#define LV2_UI__portIndex LV2_UI_PREFIX "portIndex" | |||
#define LV2_UI__portMap LV2_UI_PREFIX "portMap" | |||
#define LV2_UI__portNotification LV2_UI_PREFIX "portNotification" | |||
#define LV2_UI__portSubscribe LV2_UI_PREFIX "portSubscribe" | |||
#define LV2_UI__resize LV2_UI_PREFIX "resize" | |||
#define LV2_UI__touch LV2_UI_PREFIX "touch" | |||
#define LV2_UI__ui LV2_UI_PREFIX "ui" | |||
/** | |||
The index returned by LV2_UI_Port_Port::port_index() for unknown ports. | |||
*/ | |||
#define LV2UI_INVALID_PORT_INDEX ((uint32_t)-1) | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#else | |||
# include <stdbool.h> | |||
#endif | |||
/** | |||
A pointer to some widget or other type of UI handle. | |||
The actual type is defined by the type of the UI. | |||
*/ | |||
typedef void* LV2UI_Widget; | |||
/** | |||
A pointer to an instance of a UI. | |||
It is valid to compare this to NULL (0 for C++) but otherwise the host MUST | |||
not attempt to interpret it. The UI plugin may use it to reference internal | |||
instance data. | |||
*/ | |||
typedef void* LV2UI_Handle; | |||
/** | |||
A pointer to a controller provided by the host. | |||
It is valid to compare this to NULL (0 for C++) but otherwise the UI plugin | |||
MUST NOT attempt to interpret it. The host may use it to reference internal | |||
instance data. | |||
*/ | |||
typedef void* LV2UI_Controller; | |||
/** | |||
A pointer to opaque data for a feature. | |||
*/ | |||
typedef void* LV2UI_Feature_Handle; | |||
/** | |||
The type of the host-provided function that the UI can use to | |||
send data to a plugin's input ports. | |||
The @p buffer parameter must point to a block of data, @c buffer_size bytes | |||
large. The format of this data and how the host should use it is defined by | |||
the @p port_protocol. This buffer is owned by the UI and is only valid for | |||
the duration of this call. | |||
The @p port_protocol parameter should either be 0 or the URID for a | |||
ui:PortProtocol. If it is 0, the protocol is implicitly ui:floatProtocol, | |||
the port must be an lv2:ControlPort input, @c buffer must point to a single | |||
float value, and @c buffer_size must be sizeof(float). | |||
The UI SHOULD NOT use a PortProtocol not supported by the host (i.e. one not | |||
passed by the host as a feature), but the host MUST gracefully ignore any | |||
port_protocol it does not understand. | |||
*/ | |||
typedef void (*LV2UI_Write_Function)(LV2UI_Controller controller, | |||
uint32_t port_index, | |||
uint32_t buffer_size, | |||
uint32_t port_protocol, | |||
const void* buffer); | |||
/** | |||
The implementation of a UI. | |||
A pointer to an object of this type is returned by the lv2ui_descriptor() | |||
function. | |||
*/ | |||
typedef struct _LV2UI_Descriptor { | |||
/** | |||
The URI for this UI (not for the plugin it controls). | |||
*/ | |||
const char* URI; | |||
/** | |||
Create a new UI object and return a handle to it. This function works | |||
similarly to the instantiate() member in LV2_Descriptor. | |||
@param descriptor The descriptor for the UI that you want to instantiate. | |||
@param plugin_uri The URI of the plugin that this UI will control. | |||
@param bundle_path The path to the bundle containing the RDF data file | |||
that references this shared object file, including the trailing '/'. | |||
@param write_function A function provided by the host that the UI can use | |||
to send data to the plugin's input ports. | |||
@param controller A handle for the plugin instance that should be passed | |||
as the first parameter of @p write_function. | |||
@param widget A pointer to an LV2UI_Widget. The UI will write a widget | |||
pointer to this location (what type of widget depends on the RDF class of | |||
the UI) that will be the main UI widget. | |||
@param features An array of LV2_Feature pointers. The host must pass all | |||
feature URIs that it and the UI supports and any additional data, just | |||
like in the LV2 plugin instantiate() function. Note that UI features and | |||
plugin features are NOT necessarily the same, they just share the same | |||
data structure - this will probably not be the same array as the one the | |||
plugin host passes to a plugin. | |||
*/ | |||
LV2UI_Handle (*instantiate)(const struct _LV2UI_Descriptor* descriptor, | |||
const char* plugin_uri, | |||
const char* bundle_path, | |||
LV2UI_Write_Function write_function, | |||
LV2UI_Controller controller, | |||
LV2UI_Widget* widget, | |||
const LV2_Feature* const* features); | |||
/** | |||
Destroy the UI object and the associated widget. The host must not try | |||
to access the widget after calling this function. | |||
*/ | |||
void (*cleanup)(LV2UI_Handle ui); | |||
/** | |||
Tell the UI that something interesting has happened at a plugin port. | |||
What is interesting and how it is written to the buffer passed to this | |||
function is defined by the @p format parameter, which has the same | |||
meaning as in LV2UI_Write_Function. The only exception is ports of the | |||
class lv2:ControlPort, for which this function should be called when the | |||
port value changes (it does not have to be called for every single change | |||
if the host's UI thread has problems keeping up with the thread the | |||
plugin is running in), @p buffer_size should be 4, the buffer should | |||
contain a single IEEE-754 float, and @p format should be 0. | |||
By default, the host should only call this function for input ports of | |||
the lv2:ControlPort class. However, this can be modified by using | |||
ui:portNotification in the UI data, or the ui:portSubscribe feature. | |||
The @p buffer is only valid during the time of this function call, so if | |||
the UI wants to keep it for later use it has to copy the contents to an | |||
internal buffer. | |||
This member may be set to NULL if the UI is not interested in any | |||
port events. | |||
*/ | |||
void (*port_event)(LV2UI_Handle ui, | |||
uint32_t port_index, | |||
uint32_t buffer_size, | |||
uint32_t format, | |||
const void* buffer); | |||
/** | |||
Return a data structure associated with an extension URI, for example | |||
a struct containing additional function pointers. | |||
Avoid returning function pointers directly since standard C/C++ has no | |||
valid way of casting a void* to a function pointer. This member may be set | |||
to NULL if the UI is not interested in supporting any extensions. This is | |||
similar to the extension_data() member in LV2_Descriptor. | |||
*/ | |||
const void* (*extension_data)(const char* uri); | |||
} LV2UI_Descriptor; | |||
/** | |||
UI Resize Feature (LV2_UI__resize) | |||
This structure may be used in two ways: as a feature passed by the host via | |||
LV2UI_Descriptor::instantiate(), or as extension data provided by a UI via | |||
LV2UI_Descriptor::extension_data()). | |||
*/ | |||
typedef struct _LV2UI_Resize { | |||
/** | |||
Pointer to opaque data which must be passed to ui_resize(). | |||
*/ | |||
LV2UI_Feature_Handle handle; | |||
/** | |||
Request or advertise a size change. | |||
When this struct is provided by the host, the UI may call this | |||
function to inform the host about the size of the UI. | |||
When this struct is provided by the UI, the host may call this | |||
function to notify the UI that it should change its size accordingly. | |||
@return 0 on success. | |||
*/ | |||
int (*ui_resize)(LV2UI_Feature_Handle handle, int width, int height); | |||
} LV2UI_Resize; | |||
/** | |||
Port Map Feature (LV2_UI__portMap). | |||
This feature can be used by the UI to get the index for a port with the | |||
given symbol. This makes it possible to implement and distribute a UI | |||
separately from the plugin (since symbol is a guaranteed stable port | |||
identifier while index is not). | |||
*/ | |||
typedef struct _LV2UI_Port_Map { | |||
/** | |||
Pointer to opaque data which must be passed to ui_resize(). | |||
*/ | |||
LV2UI_Feature_Handle handle; | |||
/** | |||
Get the index for the port with the given @p symbol. | |||
@return The index of the port, or LV2_UI_INVALID_PORT_INDEX if no such | |||
port is found. | |||
*/ | |||
uint32_t (*port_index)(LV2UI_Feature_Handle handle, const char* symbol); | |||
} LV2UI_Port_Map; | |||
/** | |||
Port subscription feature (LV2_UI__portSubscribe); | |||
*/ | |||
typedef struct _LV2UI_Port_Subscribe { | |||
/** | |||
Pointer to opaque data which must be passed to ui_resize(). | |||
*/ | |||
LV2UI_Feature_Handle handle; | |||
/** | |||
Subscribe to updates for a port. | |||
This means that the host will call the UI's port_event() function when | |||
the port value changes (as defined by protocol). | |||
Calling this function with the same @p port_index and @p port_protocol | |||
as an already active subscription has no effect. | |||
@param handle The handle field of this struct. | |||
@param port_index The index of the port. | |||
@param port_protocol The URID of the ui:PortProtocol. | |||
@param features Features for this subscription. | |||
@return 0 on success. | |||
*/ | |||
uint32_t (*subscribe)(LV2UI_Feature_Handle handle, | |||
uint32_t port_index, | |||
uint32_t port_protocol, | |||
const LV2_Feature* const* features); | |||
/** | |||
Unsubscribe from updates for a port. | |||
This means that the host will cease calling calling port_event() when | |||
the port value changes. | |||
Calling this function with a @p port_index and @p port_protocol that | |||
does not refer to an active port subscription has no effect. | |||
@param handle The handle field of this struct. | |||
@param port_index The index of the port. | |||
@param port_protocol The URID of the ui:PortProtocol. | |||
@param features Features for this subscription. | |||
@return 0 on success. | |||
*/ | |||
uint32_t (*unsubscribe)(LV2UI_Feature_Handle handle, | |||
uint32_t port_index, | |||
uint32_t port_protocol, | |||
const LV2_Feature* const* features); | |||
} LV2UI_Port_Subscribe; | |||
/** | |||
A feature to notify the host the user has grabbed a UI control. | |||
*/ | |||
typedef struct _LV2UI_Touch { | |||
/** | |||
Pointer to opaque data which must be passed to ui_resize(). | |||
*/ | |||
LV2UI_Feature_Handle handle; | |||
/** | |||
Notify the host that a control has been grabbed or released. | |||
@param handle The handle field of this struct. | |||
@param port_index The index of the port associated with the control. | |||
@param grabbed If true, the control has been grabbed, otherwise the | |||
control has been released. | |||
*/ | |||
void (*touch)(LV2UI_Feature_Handle handle, | |||
uint32_t port_index, | |||
bool grabbed); | |||
} LV2UI_Touch; | |||
/** | |||
UI Idle Feature (LV2_UI__idle) | |||
This feature is an addition to the UI API that provides a callback for the | |||
host to call rapidly, e.g. to drive the idle callback of a toolkit. | |||
*/ | |||
typedef struct _LV2UI_Idle_Interface { | |||
/** | |||
Run a single iteration of the UI's idle loop. | |||
This will be called "frequently" in the UI thread at a rate appropriate | |||
for a toolkit main loop. There are no precise timing guarantees. | |||
@return 0 on success, or anything else to stop being called. | |||
*/ | |||
int (*idle)(LV2UI_Handle ui); | |||
} LV2UI_Idle_Interface; | |||
/** | |||
Peak data for a slice of time, the update format for ui:peakProtocol. | |||
*/ | |||
typedef struct _LV2UI_Peak_Data { | |||
/** | |||
The start of the measurement period. This is just a running counter | |||
that is only meaningful in comparison to previous values and must not be | |||
interpreted as an absolute time. | |||
*/ | |||
uint32_t period_start; | |||
/** | |||
The size of the measurement period, in the same units as period_start. | |||
*/ | |||
uint32_t period_size; | |||
/** | |||
The peak value for the measurement period. This should be the maximal | |||
value for abs(sample) over all the samples in the period. | |||
*/ | |||
float peak; | |||
} LV2UI_Peak_Data; | |||
/** | |||
A plugin UI programmer must include a function called "lv2ui_descriptor" | |||
with the following function prototype within the shared object file. This | |||
function will have C-style linkage (if you are using C++ this is taken care | |||
of by the 'extern "C"' clause at the top of the file). This function is | |||
loaded from the library by the UI host and called to get a | |||
LV2UI_Descriptor for the wanted plugin. | |||
Just like lv2_descriptor(), this function takes an index parameter. The | |||
index should only be used for enumeration and not as any sort of ID number - | |||
the host should just iterate from 0 and upwards until the function returns | |||
NULL or a descriptor with an URI matching the one the host is looking for. | |||
*/ | |||
LV2_SYMBOL_EXPORT | |||
const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index); | |||
/** | |||
The type of the lv2ui_descriptor() function. | |||
*/ | |||
typedef const LV2UI_Descriptor* (*LV2UI_DescriptorFunction)(uint32_t index); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif /* LV2_UI_H */ |
@@ -0,0 +1,62 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file units.h | |||
C definitions for the LV2 Units extension | |||
<http://lv2plug.in/ns/extensions/units>. | |||
*/ | |||
#ifndef LV2_UNITS_H | |||
#define LV2_UNITS_H | |||
#define LV2_UNITS_URI "http://lv2plug.in/ns/extensions/units" | |||
#define LV2_UNITS_PREFIX LV2_UNITS_URI "#" | |||
#define LV2_UNITS__Conversion LV2_UNITS_PREFIX "Conversion" | |||
#define LV2_UNITS__Unit LV2_UNITS_PREFIX "Unit" | |||
#define LV2_UNITS__bar LV2_UNITS_PREFIX "bar" | |||
#define LV2_UNITS__beat LV2_UNITS_PREFIX "beat" | |||
#define LV2_UNITS__bpm LV2_UNITS_PREFIX "bpm" | |||
#define LV2_UNITS__cent LV2_UNITS_PREFIX "cent" | |||
#define LV2_UNITS__cm LV2_UNITS_PREFIX "cm" | |||
#define LV2_UNITS__coef LV2_UNITS_PREFIX "coef" | |||
#define LV2_UNITS__conversion LV2_UNITS_PREFIX "conversion" | |||
#define LV2_UNITS__db LV2_UNITS_PREFIX "db" | |||
#define LV2_UNITS__degree LV2_UNITS_PREFIX "degree" | |||
#define LV2_UNITS__frame LV2_UNITS_PREFIX "frame" | |||
#define LV2_UNITS__hz LV2_UNITS_PREFIX "hz" | |||
#define LV2_UNITS__inch LV2_UNITS_PREFIX "inch" | |||
#define LV2_UNITS__khz LV2_UNITS_PREFIX "khz" | |||
#define LV2_UNITS__km LV2_UNITS_PREFIX "km" | |||
#define LV2_UNITS__m LV2_UNITS_PREFIX "m" | |||
#define LV2_UNITS__mhz LV2_UNITS_PREFIX "mhz" | |||
#define LV2_UNITS__midiNote LV2_UNITS_PREFIX "midiNote" | |||
#define LV2_UNITS__mile LV2_UNITS_PREFIX "mile" | |||
#define LV2_UNITS__min LV2_UNITS_PREFIX "min" | |||
#define LV2_UNITS__mm LV2_UNITS_PREFIX "mm" | |||
#define LV2_UNITS__ms LV2_UNITS_PREFIX "ms" | |||
#define LV2_UNITS__name LV2_UNITS_PREFIX "name" | |||
#define LV2_UNITS__oct LV2_UNITS_PREFIX "oct" | |||
#define LV2_UNITS__pc LV2_UNITS_PREFIX "pc" | |||
#define LV2_UNITS__prefixConversion LV2_UNITS_PREFIX "prefixConversion" | |||
#define LV2_UNITS__render LV2_UNITS_PREFIX "render" | |||
#define LV2_UNITS__s LV2_UNITS_PREFIX "s" | |||
#define LV2_UNITS__semitone12TET LV2_UNITS_PREFIX "semitone12TET" | |||
#define LV2_UNITS__symbol LV2_UNITS_PREFIX "symbol" | |||
#define LV2_UNITS__unit LV2_UNITS_PREFIX "unit" | |||
#endif /* LV2_UNITS_H */ |
@@ -0,0 +1,98 @@ | |||
/* | |||
Copyright 2008-2011 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file | |||
C header for the LV2 URI Map extension <http://lv2plug.in/ns/ext/uri-map>. | |||
This extension defines a simple mechanism for plugins to map URIs to | |||
integers, usually for performance reasons (e.g. processing events typed by | |||
URIs in real time). The expected use case is for plugins to map URIs to | |||
integers for things they 'understand' at instantiation time, and store those | |||
values for use in the audio thread without doing any string comparison. | |||
This allows the extensibility of RDF with the performance of integers (or | |||
centrally defined enumerations). | |||
*/ | |||
#ifndef LV2_URI_MAP_H | |||
#define LV2_URI_MAP_H | |||
#define LV2_URI_MAP_URI "http://lv2plug.in/ns/ext/uri-map" | |||
#include <stdint.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
Opaque pointer to host data. | |||
*/ | |||
typedef void* LV2_URI_Map_Callback_Data; | |||
/** | |||
URI Map Feature. | |||
To support this feature the host must pass an LV2_Feature struct to the | |||
plugin's instantiate method with URI "http://lv2plug.in/ns/ext/uri-map" | |||
and data pointed to an instance of this struct. | |||
*/ | |||
typedef struct { | |||
/** | |||
Opaque pointer to host data. | |||
The plugin MUST pass this to any call to functions in this struct. | |||
Otherwise, it must not be interpreted in any way. | |||
*/ | |||
LV2_URI_Map_Callback_Data callback_data; | |||
/** | |||
Get the numeric ID of a URI from the host. | |||
@param callback_data Must be the callback_data member of this struct. | |||
@param map The 'context' of this URI. Certain extensions may define a | |||
URI that must be passed here with certain restrictions on the return | |||
value (e.g. limited range). This value may be NULL if the plugin needs | |||
an ID for a URI in general. Extensions SHOULD NOT define a context | |||
unless there is a specific need to do so, e.g. to restrict the range of | |||
the returned value. | |||
@param uri The URI to be mapped to an integer ID. | |||
This function is referentially transparent; any number of calls with the | |||
same arguments is guaranteed to return the same value over the life of a | |||
plugin instance (though the same URI may return different values with a | |||
different map parameter). However, this function is not necessarily very | |||
fast: plugins SHOULD cache any IDs they might need in performance | |||
critical situations. | |||
The return value 0 is reserved and indicates that an ID for that URI | |||
could not be created for whatever reason. Extensions MAY define more | |||
precisely what this means in a certain context, but in general plugins | |||
SHOULD handle this situation as gracefully as possible. However, hosts | |||
SHOULD NOT return 0 from this function in non-exceptional circumstances | |||
(e.g. the URI map SHOULD be dynamic). Hosts that statically support only | |||
a fixed set of URIs should not expect plugins to function correctly. | |||
*/ | |||
uint32_t (*uri_to_id)(LV2_URI_Map_Callback_Data callback_data, | |||
const char* map, | |||
const char* uri); | |||
} LV2_URI_Map_Feature; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_URI_MAP_H */ |
@@ -0,0 +1,129 @@ | |||
/* | |||
Copyright 2008-2012 David Robillard <http://drobilla.net> | |||
Copyright 2011 Gabriel M. Beddingfield <gabrbedd@gmail.com> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file urid.h | |||
C header for the LV2 URID extension <http://lv2plug.in/ns/ext/urid> | |||
*/ | |||
#ifndef LV2_URID_H | |||
#define LV2_URID_H | |||
#define LV2_URID_URI "http://lv2plug.in/ns/ext/urid" | |||
#define LV2_URID_PREFIX LV2_URID_URI "#" | |||
#define LV2_URID__map LV2_URID_PREFIX "map" | |||
#define LV2_URID__unmap LV2_URID_PREFIX "unmap" | |||
/* Legacy defines */ | |||
#define LV2_URID_MAP_URI LV2_URID__map | |||
#define LV2_URID_UNMAP_URI LV2_URID__unmap | |||
#include <stdint.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
Opaque pointer to host data for LV2_URID_Map. | |||
*/ | |||
typedef void* LV2_URID_Map_Handle; | |||
/** | |||
Opaque pointer to host data for LV2_URID_Unmap. | |||
*/ | |||
typedef void* LV2_URID_Unmap_Handle; | |||
/** | |||
URI mapped to an integer. | |||
*/ | |||
typedef uint32_t LV2_URID; | |||
/** | |||
URID Map Feature (LV2_URID__map) | |||
*/ | |||
typedef struct _LV2_URID_Map { | |||
/** | |||
Opaque pointer to host data. | |||
This MUST be passed to map_uri() whenever it is called. | |||
Otherwise, it must not be interpreted in any way. | |||
*/ | |||
LV2_URID_Map_Handle handle; | |||
/** | |||
Get the numeric ID of a URI. | |||
If the ID does not already exist, it will be created. | |||
This function is referentially transparent; any number of calls with the | |||
same arguments is guaranteed to return the same value over the life of a | |||
plugin instance. Note, however, that several URIs MAY resolve to the | |||
same ID if the host considers those URIs equivalent. | |||
This function is not necessarily very fast or RT-safe: plugins SHOULD | |||
cache any IDs they might need in performance critical situations. | |||
The return value 0 is reserved and indicates that an ID for that URI | |||
could not be created for whatever reason. However, hosts SHOULD NOT | |||
return 0 from this function in non-exceptional circumstances (i.e. the | |||
URI map SHOULD be dynamic). | |||
@param handle Must be the callback_data member of this struct. | |||
@param uri The URI to be mapped to an integer ID. | |||
*/ | |||
LV2_URID (*map)(LV2_URID_Map_Handle handle, | |||
const char* uri); | |||
} LV2_URID_Map; | |||
/** | |||
URI Unmap Feature (LV2_URID__unmap) | |||
*/ | |||
typedef struct _LV2_URID_Unmap { | |||
/** | |||
Opaque pointer to host data. | |||
This MUST be passed to unmap() whenever it is called. | |||
Otherwise, it must not be interpreted in any way. | |||
*/ | |||
LV2_URID_Unmap_Handle handle; | |||
/** | |||
Get the URI for a previously mapped numeric ID. | |||
Returns NULL if @p urid is not yet mapped. Otherwise, the corresponding | |||
URI is returned in a canonical form. This MAY not be the exact same | |||
string that was originally passed to LV2_URID_Map::map(), but it MUST be | |||
an identical URI according to the URI syntax specification (RFC3986). A | |||
non-NULL return for a given @p urid will always be the same for the life | |||
of the plugin. Plugins that intend to perform string comparison on | |||
unmapped URIs SHOULD first canonicalise URI strings with a call to | |||
map_uri() followed by a call to unmap_uri(). | |||
@param handle Must be the callback_data member of this struct. | |||
@param urid The ID to be mapped back to the URI string. | |||
*/ | |||
const char* (*unmap)(LV2_URID_Unmap_Handle handle, | |||
LV2_URID urid); | |||
} LV2_URID_Unmap; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_URID_H */ |
@@ -0,0 +1,158 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
*/ | |||
/** | |||
@file worker.h C header for the LV2 Worker extension | |||
<http://lv2plug.in/ns/ext/worker>. | |||
*/ | |||
#ifndef LV2_WORKER_H | |||
#define LV2_WORKER_H | |||
#include <stdint.h> | |||
#include "lv2.h" | |||
#define LV2_WORKER_URI "http://lv2plug.in/ns/ext/worker" | |||
#define LV2_WORKER_PREFIX LV2_WORKER_URI "#" | |||
#define LV2_WORKER__interface LV2_WORKER_PREFIX "interface" | |||
#define LV2_WORKER__schedule LV2_WORKER_PREFIX "schedule" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
A status code for worker functions. | |||
*/ | |||
typedef enum { | |||
LV2_WORKER_SUCCESS = 0, /**< Completed successfully. */ | |||
LV2_WORKER_ERR_UNKNOWN = 1, /**< Unknown error. */ | |||
LV2_WORKER_ERR_NO_SPACE = 2 /**< Failed due to lack of space. */ | |||
} LV2_Worker_Status; | |||
typedef void* LV2_Worker_Respond_Handle; | |||
/** | |||
A function to respond to run() from the worker method. | |||
The @p data MUST be safe for the host to copy and later pass to | |||
work_response(), and the host MUST guarantee that it will be eventually | |||
passed to work_response() if this function returns LV2_WORKER_SUCCESS. | |||
*/ | |||
typedef LV2_Worker_Status (*LV2_Worker_Respond_Function)( | |||
LV2_Worker_Respond_Handle handle, | |||
uint32_t size, | |||
const void* data); | |||
/** | |||
LV2 Plugin Worker Interface. | |||
This is the interface provided by the plugin to implement a worker method. | |||
The plugin's extension_data() method should return an LV2_Worker_Interface | |||
when called with LV2_WORKER__interface as its argument. | |||
*/ | |||
typedef struct _LV2_Worker_Interface { | |||
/** | |||
The worker method. This is called by the host in a non-realtime context | |||
as requested, possibly with an arbitrary message to handle. | |||
A response can be sent to run() using @p respond. The plugin MUST NOT | |||
make any assumptions about which thread calls this method, other than | |||
the fact that there are no real-time requirements. | |||
@param instance The LV2 instance this is a method on. | |||
@param respond A function for sending a response to run(). | |||
@param handle Must be passed to @p respond if it is called. | |||
@param size The size of @p data. | |||
@param data Data from run(), or NULL. | |||
*/ | |||
LV2_Worker_Status (*work)(LV2_Handle instance, | |||
LV2_Worker_Respond_Function respond, | |||
LV2_Worker_Respond_Handle handle, | |||
uint32_t size, | |||
const void* data); | |||
/** | |||
Handle a response from the worker. This is called by the host in the | |||
run() context when a response from the worker is ready. | |||
@param instance The LV2 instance this is a method on. | |||
@param size The size of @p body. | |||
@param body Message body, or NULL. | |||
*/ | |||
LV2_Worker_Status (*work_response)(LV2_Handle instance, | |||
uint32_t size, | |||
const void* body); | |||
/** | |||
Called when all responses for this cycle have been delivered. | |||
Since work_response() may be called after run() finished, this provides | |||
a hook for code that must run after the cycle is completed. | |||
This field may be NULL if the plugin has no use for it. Otherwise, the | |||
host MUST call it after every run(), regardless of whether or not any | |||
responses were sent that cycle. | |||
*/ | |||
LV2_Worker_Status (*end_run)(LV2_Handle instance); | |||
} LV2_Worker_Interface; | |||
typedef void* LV2_Worker_Schedule_Handle; | |||
typedef struct _LV2_Worker_Schedule { | |||
/** | |||
Opaque host data. | |||
*/ | |||
LV2_Worker_Schedule_Handle handle; | |||
/** | |||
Request from run() that the host call the worker. | |||
This function is in the audio threading class. It should be called from | |||
run() to request that the host call the work() method in a non-realtime | |||
context with the given arguments. | |||
This function is always safe to call from run(), but it is not | |||
guaranteed that the worker is actually called from a different thread. | |||
In particular, when free-wheeling (e.g. for offline rendering), the | |||
worker may be executed immediately. This allows single-threaded | |||
processing with sample accuracy and avoids timing problems when run() is | |||
executing much faster or slower than real-time. | |||
Plugins SHOULD be written in such a way that if the worker runs | |||
immediately, and responses from the worker are delivered immediately, | |||
the effect of the work takes place immediately with sample accuracy. | |||
The @p data MUST be safe for the host to copy and later pass to work(), | |||
and the host MUST guarantee that it will be eventually passed to work() | |||
if this function returns LV2_WORKER_SUCCESS. | |||
@param handle The handle field of this struct. | |||
@param size The size of @p data. | |||
@param data Message to pass to work(), or NULL. | |||
*/ | |||
LV2_Worker_Status (*schedule_work)(LV2_Worker_Schedule_Handle handle, | |||
uint32_t size, | |||
const void* data); | |||
} LV2_Worker_Schedule; | |||
#ifdef __cplusplus | |||
} /* extern "C" */ | |||
#endif | |||
#endif /* LV2_WORKER_H */ |
@@ -0,0 +1,279 @@ | |||
/* | |||
* aeffectx.h - simple header to allow VeSTige compilation and eventually work | |||
* | |||
* Copyright (c) 2006 Javier Serrano Polo <jasp00/at/users.sourceforge.net> | |||
* | |||
* This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net | |||
* | |||
* 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 (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 (see COPYING); if not, write to the | |||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |||
* Boston, MA 02110-1301 USA. | |||
* | |||
*/ | |||
#include <stdint.h> | |||
#ifndef _AEFFECTX_H | |||
#define _AEFFECTX_H | |||
#define CCONST(a, b, c, d)( ( ( (int) a ) << 24 ) | \ | |||
( ( (int) b ) << 16 ) | \ | |||
( ( (int) c ) << 8 ) | \ | |||
( ( (int) d ) << 0 ) ) | |||
#define audioMasterAutomate 0 | |||
#define audioMasterVersion 1 | |||
#define audioMasterCurrentId 2 | |||
#define audioMasterIdle 3 | |||
#define audioMasterPinConnected 4 | |||
// unsupported? 5 | |||
#define audioMasterWantMidi 6 | |||
#define audioMasterGetTime 7 | |||
#define audioMasterProcessEvents 8 | |||
#define audioMasterSetTime 9 | |||
#define audioMasterTempoAt 10 | |||
#define audioMasterGetNumAutomatableParameters 11 | |||
#define audioMasterGetParameterQuantization 12 | |||
#define audioMasterIOChanged 13 | |||
#define audioMasterNeedIdle 14 | |||
#define audioMasterSizeWindow 15 | |||
#define audioMasterGetSampleRate 16 | |||
#define audioMasterGetBlockSize 17 | |||
#define audioMasterGetInputLatency 18 | |||
#define audioMasterGetOutputLatency 19 | |||
#define audioMasterGetPreviousPlug 20 | |||
#define audioMasterGetNextPlug 21 | |||
#define audioMasterWillReplaceOrAccumulate 22 | |||
#define audioMasterGetCurrentProcessLevel 23 | |||
#define audioMasterGetAutomationState 24 | |||
#define audioMasterOfflineStart 25 | |||
#define audioMasterOfflineRead 26 | |||
#define audioMasterOfflineWrite 27 | |||
#define audioMasterOfflineGetCurrentPass 28 | |||
#define audioMasterOfflineGetCurrentMetaPass 29 | |||
#define audioMasterSetOutputSampleRate 30 | |||
// unsupported? 31 | |||
#define audioMasterGetSpeakerArrangement 31 // deprecated in 2.4? | |||
#define audioMasterGetVendorString 32 | |||
#define audioMasterGetProductString 33 | |||
#define audioMasterGetVendorVersion 34 | |||
#define audioMasterVendorSpecific 35 | |||
#define audioMasterSetIcon 36 | |||
#define audioMasterCanDo 37 | |||
#define audioMasterGetLanguage 38 | |||
#define audioMasterOpenWindow 39 | |||
#define audioMasterCloseWindow 40 | |||
#define audioMasterGetDirectory 41 | |||
#define audioMasterUpdateDisplay 42 | |||
#define audioMasterBeginEdit 43 | |||
#define audioMasterEndEdit 44 | |||
#define audioMasterOpenFileSelector 45 | |||
#define audioMasterCloseFileSelector 46 // currently unused | |||
#define audioMasterEditFile 47 // currently unused | |||
#define audioMasterGetChunkFile 48 // currently unused | |||
#define audioMasterGetInputSpeakerArrangement 49 // currently unused | |||
#define effFlagsHasEditor 1 | |||
#define effFlagsCanReplacing (1 << 4) // very likely | |||
#define effFlagsIsSynth (1 << 8) // currently unused | |||
#define effOpen 0 | |||
#define effClose 1 // currently unused | |||
#define effSetProgram 2 // currently unused | |||
#define effGetProgram 3 // currently unused | |||
#define effGetProgramName 5 // currently unused | |||
#define effGetParamName 8 // currently unused | |||
#define effSetSampleRate 10 | |||
#define effSetBlockSize 11 | |||
#define effMainsChanged 12 | |||
#define effEditGetRect 13 | |||
#define effEditOpen 14 | |||
#define effEditClose 15 | |||
#define effEditIdle 19 | |||
#define effEditTop 20 | |||
#define effProcessEvents 25 | |||
#define effGetEffectName 45 | |||
#define effGetVendorString 47 | |||
#define effGetProductString 48 | |||
#define effGetVendorVersion 49 | |||
#define effCanDo 51 // currently unused | |||
/* from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||
#define effGetParameterProperties 56 | |||
#define effGetVstVersion 58 // currently unused | |||
#define kEffectMagic (CCONST( 'V', 's', 't', 'P' )) | |||
#define kVstLangEnglish 1 | |||
#define kVstMidiType 1 | |||
#define kVstTempoValid (1 << 10) | |||
#define kVstTransportPlaying (1 << 1) | |||
struct RemoteVstPlugin; | |||
#define kVstNanosValid (1 << 8) | |||
#define kVstPpqPosValid (1 << 9) | |||
#define kVstTempoValid (1 << 10) | |||
#define kVstBarsValid (1 << 11) | |||
#define kVstCyclePosValid (1 << 12) | |||
#define kVstTimeSigValid (1 << 13) | |||
#define kVstSmpteValid (1 << 14) | |||
#define kVstClockValid (1 << 15) | |||
struct _VstMidiEvent | |||
{ | |||
// 00 | |||
int type; | |||
// 04 | |||
int byteSize; | |||
// 08 | |||
int deltaFrames; | |||
// 0c? | |||
int flags; | |||
// 10? | |||
int noteLength; | |||
// 14? | |||
int noteOffset; | |||
// 18 | |||
char midiData[4]; | |||
// 1c? | |||
char detune; | |||
// 1d? | |||
char noteOffVelocity; | |||
// 1e? | |||
char reserved1; | |||
// 1f? | |||
char reserved2; | |||
}; | |||
typedef struct _VstMidiEvent VstMidiEvent; | |||
struct _VstEvent | |||
{ | |||
char dump[sizeof (VstMidiEvent)]; | |||
}; | |||
typedef struct _VstEvent VstEvent; | |||
struct _VstEvents | |||
{ | |||
// 00 | |||
int numEvents; | |||
// 04 | |||
void *reserved; | |||
// 08 | |||
VstEvent * events[2]; | |||
}; | |||
typedef struct _VstEvents VstEvents; | |||
/* this struct taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||
struct _VstParameterProperties | |||
{ | |||
float stepFloat; | |||
float smallStepFloat; | |||
float largeStepFloat; | |||
char label[64]; | |||
int32_t flags; | |||
int32_t minInteger; | |||
int32_t maxInteger; | |||
int32_t stepInteger; | |||
int32_t largeStepInteger; | |||
char shortLabel[8]; | |||
}; | |||
typedef struct _VstParameterProperties VstParameterProperties; | |||
/* this enum taken from http://asseca.com/vst-24-specs/efGetParameterProperties.html */ | |||
enum VstParameterFlags | |||
{ | |||
kVstParameterIsSwitch = 1 << 0, /* parameter is a switch (on/off) */ | |||
kVstParameterUsesIntegerMinMax = 1 << 1, /* minInteger, maxInteger valid */ | |||
kVstParameterUsesFloatStep = 1 << 2, /* stepFloat, smallStepFloat, largeStepFloat valid */ | |||
kVstParameterUsesIntStep = 1 << 3, /* stepInteger, largeStepInteger valid */ | |||
kVstParameterSupportsDisplayIndex = 1 << 4, /* displayIndex valid */ | |||
kVstParameterSupportsDisplayCategory = 1 << 5, /* category, etc. valid */ | |||
kVstParameterCanRamp = 1 << 6 /* set if parameter value can ramp up/down */ | |||
}; | |||
struct _AEffect | |||
{ | |||
// Never use virtual functions!!! | |||
// 00-03 | |||
int magic; | |||
// dispatcher 04-07 | |||
intptr_t (* dispatcher) (struct _AEffect *, int, int, intptr_t, void *, float); | |||
// process, quite sure 08-0b | |||
void (* process) (struct _AEffect *, float **, float **, int); | |||
// setParameter 0c-0f | |||
void (* setParameter) (struct _AEffect *, int, float); | |||
// getParameter 10-13 | |||
float (* getParameter) (struct _AEffect *, int); | |||
// programs 14-17 | |||
int numPrograms; | |||
// Params 18-1b | |||
int numParams; | |||
// Input 1c-1f | |||
int numInputs; | |||
// Output 20-23 | |||
int numOutputs; | |||
// flags 24-27 | |||
int flags; | |||
// Fill somewhere 28-2b | |||
void *ptr1; | |||
void *ptr2; | |||
// Zeroes 2c-2f 30-33 34-37 38-3b | |||
char empty3[4 + 4 + 4]; | |||
// 1.0f 3c-3f | |||
float unkown_float; | |||
// An object? pointer 40-43 | |||
void *ptr3; | |||
// Zeroes 44-47 | |||
void *user; | |||
// Id 48-4b | |||
int32_t uniqueID; | |||
// Don't know 4c-4f | |||
char unknown1[4]; | |||
// processReplacing 50-53 | |||
void (* processReplacing) (struct _AEffect *, float **, float **, int); | |||
}; | |||
typedef struct _AEffect AEffect; | |||
struct _VstTimeInfo | |||
{ | |||
// 00 | |||
double samplePos; | |||
// 08 | |||
double sampleRate; | |||
// unconfirmed 10 18 | |||
char empty1[8 + 8]; | |||
// 20? | |||
double tempo; | |||
// unconfirmed 28 30 38 | |||
char empty2[8 + 8 + 8]; | |||
// 40? | |||
int timeSigNumerator; | |||
// 44? | |||
int timeSigDenominator; | |||
// unconfirmed 48 4c 50 | |||
char empty3[4 + 4 + 4]; | |||
// 54 | |||
int flags; | |||
}; | |||
typedef struct _VstTimeInfo VstTimeInfo; | |||
typedef intptr_t (* audioMasterCallback) (AEffect *, int32_t, int32_t, intptr_t, void *, float); | |||
#endif |