Skip to content

Commit 3ae9090

Browse files
committed
Merge branch 'futex-events' into develop
2 parents f4452c9 + 154a2c7 commit 3ae9090

29 files changed

+219
-314
lines changed

CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ project(${PROJECT_NAME})
55

66
# Project version
77
set(VERSION_MAJOR 1)
8-
set(VERSION_MINOR 0)
9-
set(VERSION_PATCH 2)
8+
set(VERSION_MINOR 1)
9+
set(VERSION_PATCH 0)
1010

1111
# Set plugin shared library base name
1212
set(PLUGIN_BASENAME ${PROJECT_NAME}-plugin)

README

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Building the source
3333
mkdir build && cd build
3434
cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX=/opt/airwave -DVSTSDK_PATH=${HOME}/VST3\ SDK ..
3535
make
36-
make install
36+
sudo make install
3737

3838
Of course, you can change the CMAKE_INSTALL_PREFIX as you like.
3939

README.md

+56-45
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,6 @@
22
Airwave is a [WINE](https://www.winehq.org/)-based VST bridge, that allows for the use of Windows 32- and 64-bit VST 2.4 audio plugins with Linux VST hosts.
33
Due to the use of shared memory, only one extra copying is made for each data transfer. Airwave also uses the XEMBED protocol to correctly embed the plugin editor into the host window.
44

5-
## Compatibility
6-
The following list is not complete. It contains only plugins, that have been tested by me or by people, who sent me a report.
7-
8-
VST-Plugins | works? | Notes |
9-
------------:|:----------:|:-------|
10-
Blue Cat Audio Oscilloscope Multi | no | doesn't work with wine
11-
Credland Audio BigKick | no | doesn't work with wine
12-
FabFilter Total bundle | yes | haven't tested them all
13-
Image-Line Harmless | yes |
14-
Image-Line Sytrus | yes |
15-
LennarDigital Sylenth1 | no | doesn't work with wine
16-
LePou Plugins | yes | LeCab2 has slight GUI redrawing issues
17-
NI Absynth | yes |
18-
NI FM8 | yes |
19-
NI Guitar Rig 5 | yes | activation doesn't work
20-
NI Kontakt 5 | mostly | up to v5.3.1, can import libraries only in Windows XP mode
21-
NI Massive | yes | only 32-bit
22-
NI Reaktor 5 | yes |
23-
Peavey Revalver Mark III.V | yes |
24-
ReFX Nexus2 | yes |
25-
ReFX Vanguard | yes |
26-
Reveal Sound Spire | yes | starting form 1.0.19 the GUI doesn't appear (wine issue)
27-
Sonic Academy A.N.A. | yes |
28-
Sonic Academy KICK | yes |
29-
Smartelectronix s(M)exoscope | yes |
30-
Synth1 by Ichiro Toda | yes |
31-
Tone2 FireBird | yes |
32-
Tone2 Nemesis | yes |
33-
Tone2 Saurus | yes |
34-
u-he A.C.E. | yes | Linux version is also available
35-
u-he Bazille | yes | Linux version is also available
36-
u-he Diva | yes | Linux version is also available
37-
u-he Hive | yes | Linux version is also available
38-
u-he Presswerk | yes | Linux version is also available
39-
u-he Satin | yes | Linux version is also available
40-
u-he Uhbik | yes | Linux version is also available
41-
u-he Zebra2 | yes | Linux version is also available
42-
Variety of Sound plugins | yes |
43-
Voxengo SPAN | yes |
44-
Voxengo SPAN Pro | mostly | inter plugin routing doesn't work (architecture issue)
45-
Xfer Serum | partly | the GUI doesn't appear (wine issue), but audio works
46-
475
## Requirements
486
- WINE, supporting XEMBED protocol (versions greater than 1.7.19 were tested,
497
but earlier versions also may work)
@@ -83,7 +41,7 @@ but earlier versions also may work)
8341
mkdir build && cd build
8442
cmake -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX=/opt/airwave -DVSTSDK_PATH=${HOME}/VST3\ SDK ..
8543
make
86-
make install
44+
sudo make install
8745
```
8846
8947
Of course, you can change the CMAKE_INSTALL_PREFIX as you like.
@@ -102,12 +60,65 @@ Of course, you can change the CMAKE_INSTALL_PREFIX as you like.
10260
10361
## Under the hood
10462
The bridge consists of four components:
105-
- Plugin endpoint (airwave-plugin-<arch>.so)
106-
- Host endpoint (airwave-host-<arch>.exe.so and airwave-host-<arch>.exe launcher script)
63+
- Plugin endpoint (airwave-plugin.so)
64+
- Host endpoint (airwave-host-{arch}.exe.so and airwave-host-{arch}.exe launcher script)
10765
- Configuration file (${XDG_CONFIG_PATH}/airwave/airwave.conf)
10866
- GUI configurator (airwave-manager)
10967
11068
When the airwave-plugin is loaded by the VST host, it obtains its absolute path and use it as the key to get the linked VST DLL from the configuration. Then it starts the airwave-host process and passes the path to the linked VST file. The airwave-host loads the VST DLL and works as a fake VST host. Starting from this point, the airwave-plugin and airwave-host act together like a proxy, translating commands between the native VST host and the Windows VST plugin.
11169
11270
## Known issues
11371
- Due to a bug in WINE, there is some hacking involved when embedding the editor window. There is a chance that you get a black window instead of the plugin GUI. Also some areas might not update correctly when increasing the window size. On some hosts (Bitwig Studio for example) this can be solved by closing and re-opening the plugin window.
72+
73+
## Compatibility
74+
The following list is not complete. It contains only plugins, that have been tested by me or by people, who sent me a report.
75+
76+
VST-Plugins | works? | Notes |
77+
------------:|:----------:|:-------|
78+
AlgoMusic CZythia | yes |
79+
Aly James LAB OB-Xtreme | yes |
80+
Blue Cat Audio Oscilloscope Multi | no | doesn't work with wine
81+
Credland Audio BigKick | no | doesn't work with wine
82+
FabFilter Total bundle | yes | haven't tested them all
83+
Green Oak Software Crystal | yes |
84+
Image-Line Harmless | yes |
85+
Image-Line Sytrus | yes |
86+
LennarDigital Sylenth1 | no | doesn't work with wine
87+
LePou Plugins | yes | LeCab2 has slight GUI redrawing issues
88+
NI Absynth | yes |
89+
NI FM8 | yes |
90+
NI Guitar Rig 5 | yes | activation doesn't work
91+
NI Kontakt 5 | mostly | up to v5.3.1, can import libraries only in Windows XP mode
92+
NI Massive | yes | only 32-bit
93+
NI Reaktor 5 | yes |
94+
Magnus Choir | yes |
95+
Martin Lüders pg8x | yes |
96+
Meesha Damatriks | yes |
97+
Odo Synths Double Six | partly | GUI doesn't show, but presets are available and functional
98+
Peavey Revalver Mark III.V | yes |
99+
ReFX Nexus2 | yes |
100+
ReFX Vanguard | yes |
101+
Reveal Sound Spire | yes | starting form 1.0.19 the GUI doesn't appear (wine issue)
102+
Sonic Academy A.N.A. | yes |
103+
Sonic Academy KICK | yes |
104+
Sonic Cat LFX-1310 | yes |
105+
Sonic Charge Cyclone | yes |
106+
Smartelectronix s(M)exoscope | yes |
107+
SQ8L by Siegfried Kullmann | yes |
108+
SuperWave P8 | yes |
109+
Synth1 by Ichiro Toda | yes |
110+
Tone2 FireBird | yes |
111+
Tone2 Nemesis | yes |
112+
Tone2 Saurus | yes |
113+
u-he A.C.E. | yes | Linux version is also available
114+
u-he Bazille | yes | Linux version is also available
115+
u-he Diva | yes | Linux version is also available
116+
u-he Hive | yes | Linux version is also available
117+
u-he Presswerk | yes | Linux version is also available
118+
u-he Satin | yes | Linux version is also available
119+
u-he Uhbik | yes | Linux version is also available
120+
u-he Zebra2 | yes | Linux version is also available
121+
Variety of Sound plugins | yes |
122+
Voxengo SPAN | yes |
123+
Voxengo SPAN Pro | mostly | inter plugin routing doesn't work (architecture issue)
124+
Xfer Serum | no | the GUI doesn't appear (wine issue), but audio works

src/common/dataport.cpp

+10-53
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,7 @@ bool DataPort::create(size_t frameSize)
4747
return false;
4848
}
4949

50-
ControlBlock* control = controlBlock();
51-
sem_init(&control->request, 1, 0);
52-
sem_init(&control->response, 1, 0);
50+
new (controlBlock()) ControlBlock;
5351

5452
frameSize_ = frameSize;
5553
return true;
@@ -89,9 +87,9 @@ void DataPort::disconnect()
8987
{
9088
if(!isNull()) {
9189
if(!isConnected()) {
92-
ControlBlock* control = controlBlock();
93-
sem_destroy(&control->request);
94-
sem_destroy(&control->response);
90+
// ControlBlock* control = controlBlock();
91+
// sem_destroy(&control->request);
92+
// sem_destroy(&control->response);
9593
}
9694

9795
shmdt(buffer_);
@@ -142,31 +140,27 @@ void* DataPort::frameBuffer()
142140

143141
void DataPort::sendRequest()
144142
{
145-
if(!isNull()) {
146-
if(sem_post(&controlBlock()->request) != 0)
147-
ERROR("sem_post() call failed: %s", strerror(errno));
148-
}
143+
if(!isNull())
144+
controlBlock()->request.post();
149145
}
150146

151147

152148
void DataPort::sendResponse()
153149
{
154-
if(!isNull()) {
155-
if(sem_post(&controlBlock()->response) != 0)
156-
ERROR("sem_post() call failed: %s", strerror(errno));
157-
}
150+
if(!isNull())
151+
controlBlock()->response.post();
158152
}
159153

160154

161155
bool DataPort::waitRequest(int msecs)
162156
{
163-
return waitForReady(&controlBlock()->request, msecs);
157+
return controlBlock()->request.wait(msecs);
164158
}
165159

166160

167161
bool DataPort::waitResponse(int msecs)
168162
{
169-
return waitForReady(&controlBlock()->response, msecs);
163+
return controlBlock()->response.wait(msecs);
170164
}
171165

172166

@@ -176,41 +170,4 @@ DataPort::ControlBlock* DataPort::controlBlock()
176170
}
177171

178172

179-
bool DataPort::waitForReady(sem_t* semaphore, int msecs)
180-
{
181-
if(isNull())
182-
return false;
183-
184-
if(msecs < 0) {
185-
if(sem_wait(semaphore) != 0) {
186-
ERROR("sem_wait() call failed: %d", errno);
187-
return false;
188-
}
189-
}
190-
else {
191-
int seconds = msecs / 1000;
192-
msecs %= 1000;
193-
194-
timespec tm;
195-
clock_gettime(CLOCK_REALTIME, &tm);
196-
tm.tv_sec += seconds;
197-
tm.tv_nsec += msecs * 1000000;
198-
199-
if(tm.tv_nsec >= 1000000000L) {
200-
tm.tv_sec++;
201-
tm.tv_nsec -= 1000000000L;
202-
}
203-
204-
if(sem_timedwait(semaphore, &tm) != 0) {
205-
if(errno != ETIMEDOUT)
206-
ERROR("sem_timedwait() call failed: %d", errno);
207-
208-
return false;
209-
}
210-
}
211-
212-
return true;
213-
}
214-
215-
216173
} // namespace Airwave

src/common/dataport.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef COMMON_DATAPORT_H
22
#define COMMON_DATAPORT_H
33

4-
#include <semaphore.h>
4+
#include "common/event.h"
55
#include "common/types.h"
66

77

@@ -35,16 +35,15 @@ class DataPort {
3535

3636
private:
3737
struct ControlBlock {
38-
sem_t request;
39-
sem_t response;
40-
} __attribute__((packed));
38+
Event request;
39+
Event response;
40+
};
4141

4242
int id_;
4343
size_t frameSize_;
4444
void* buffer_;
4545

4646
ControlBlock* controlBlock();
47-
bool waitForReady(sem_t* semaphore, int msecs = -1);
4847
};
4948

5049

src/common/event.cpp

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#include "event.h"
2+
3+
#include <errno.h>
4+
#include <syscall.h>
5+
#include <time.h>
6+
#include <unistd.h>
7+
#include <linux/futex.h>
8+
9+
10+
#define futex_wait(futex, count, timeout) \
11+
(syscall(SYS_futex, futex, FUTEX_WAIT, count, timeout, nullptr, 0) == 0)
12+
13+
#define futex_post(futex, count) \
14+
(syscall(SYS_futex, futex, FUTEX_WAKE, count, nullptr, nullptr, 0) == 0)
15+
16+
17+
Event::Event() :
18+
count_(0)
19+
{
20+
}
21+
22+
23+
Event::~Event()
24+
{
25+
// FIXME The current implementation is not correct as it wakes only the one waiter.
26+
futex_post(&count_, 1);
27+
}
28+
29+
30+
bool Event::wait(int msecs)
31+
{
32+
timespec* timeout = nullptr;
33+
timespec tm;
34+
35+
if(msecs >= 0) {
36+
int seconds = msecs / 1000;
37+
msecs %= 1000;
38+
39+
tm.tv_sec = seconds;
40+
tm.tv_nsec = msecs * 1000000;
41+
42+
timeout = &tm;
43+
}
44+
45+
while(count_ == 0) {
46+
if(!futex_wait(&count_, 0, timeout) && errno != EWOULDBLOCK)
47+
return false;
48+
}
49+
50+
count_--;
51+
return true;
52+
}
53+
54+
55+
void Event::post()
56+
{
57+
count_++;
58+
futex_post(&count_, 1);
59+
}

src/common/event.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#ifndef COMMON_EVENT_H
2+
#define COMMON_EVENT_H
3+
4+
#include <atomic>
5+
6+
#ifdef bool
7+
#undef bool
8+
#endif
9+
10+
11+
class Event {
12+
public:
13+
static const int kInfinite = -1;
14+
15+
Event();
16+
~Event();
17+
18+
bool wait(int msecs = kInfinite);
19+
void post();
20+
21+
private:
22+
std::atomic<int> count_;
23+
};
24+
25+
26+
#endif // COMMON_EVENT_H

0 commit comments

Comments
 (0)