added (experimental) driver support

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2937 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
mahlzeit 2003-03-17 22:33:38 +00:00
parent 30ace1d7c5
commit 94d1c0ea39
8 changed files with 464 additions and 173 deletions

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <Application.h>
#include <Bitmap.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Path.h>
#include <Resources.h>
#include <Roster.h>
#include "DeviceWatcher.h"
#include "PortDrivers.h"
#include "debug.h"
//------------------------------------------------------------------------------
DeviceWatcher::DeviceWatcher()
{
largeIcon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
miniIcon = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
app_info info;
be_app->GetAppInfo(&info);
BFile file(&info.ref, B_READ_ONLY);
BResources res;
if (res.SetTo(&file) == B_OK)
{
size_t size;
const void* bits;
bits = res.LoadResource('ICON', 10, &size);
largeIcon->SetBits(bits, size, 0, B_CMAP8);
bits = res.LoadResource('MICN', 11, &size);
miniIcon->SetBits(bits, size, 0, B_CMAP8);
}
}
//------------------------------------------------------------------------------
DeviceWatcher::~DeviceWatcher()
{
delete largeIcon;
delete miniIcon;
}
//------------------------------------------------------------------------------
void DeviceWatcher::Start()
{
// We need to do this from a separate thread, otherwise we will deadlock.
// The reason is that we instantiate a BMidiRoster object, which sends a
// message to the midi_server to register itself, and blocks until it gets
// a response. But since we _are_ the midi_server we will never be able to
// send that response if our main thread is already blocking.
resume_thread(spawn_thread(
SpawnThread, "DeviceWatcher", B_NORMAL_PRIORITY, this));
}
//------------------------------------------------------------------------------
int32 DeviceWatcher::SpawnThread(void* data)
{
((DeviceWatcher*) data)->ScanDevices("/dev/midi");
return 0;
}
//------------------------------------------------------------------------------
void DeviceWatcher::ScanDevices(const char* path)
{
BDirectory dir(path);
if (dir.InitCheck() == B_OK)
{
BEntry entry;
while (dir.GetNextEntry(&entry) == B_OK)
{
BPath name;
entry.GetPath(&name);
if (entry.IsDirectory())
{
ScanDevices(name.Path());
}
else
{
int fd = open(name.Path(), O_RDWR | O_EXCL);
if (fd >= 0)
{
BMidiEndpoint* endp;
endp = new MidiPortConsumer(fd, name.Path());
SetIcons(endp);
endp->Register();
endp = new MidiPortProducer(fd, name.Path());
SetIcons(endp);
endp->Register();
}
}
}
}
}
//------------------------------------------------------------------------------
void DeviceWatcher::SetIcons(BMidiEndpoint* endp)
{
BMessage msg;
msg.AddData(
"be:large_icon", 'ICON', largeIcon->Bits(), largeIcon->BitsLength());
msg.AddData(
"be:mini_icon", 'MICN', miniIcon->Bits(), miniIcon->BitsLength());
endp->SetProperties(&msg);
}
//------------------------------------------------------------------------------

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef DEVICE_WATCHER_H
#define DEVICE_WATCHER_H
class BBitmap;
class BMidiEndpoint;
class DeviceWatcher
{
public:
DeviceWatcher();
~DeviceWatcher();
void Start();
private:
static int32 SpawnThread(void* data);
void ScanDevices(const char* path);
void SetIcons(BMidiEndpoint* endp);
BBitmap* largeIcon;
BBitmap* miniIcon;
};
#endif // DEVICE_WATCHER_H

View File

@ -8,8 +8,11 @@ AddResources midi_server :
Server midi_server :
MidiServerApp.cpp
DeviceWatcher.cpp
PortDrivers.cpp
;
LinkSharedOSLibs midi_server :
be
midi2
;

View File

@ -24,6 +24,7 @@
#include "debug.h"
#include "MidiServerApp.h"
#include "PortDrivers.h"
#include "ServerDefs.h"
#include "protocol.h"
@ -35,6 +36,7 @@ MidiServerApp::MidiServerApp()
TRACE(("Running OpenBeOS MIDI server"))
nextId = 1;
devWatcher.Start();
}
//------------------------------------------------------------------------------

View File

@ -26,6 +26,8 @@
#include <Application.h>
#include <List.h>
#include "DeviceWatcher.h"
struct app_t;
struct endpoint_t;
@ -137,6 +139,9 @@ private:
// The ID we will assign to the next new endpoint.
int32 nextId;
// Creates endpoints for /dev/midi drivers.
DeviceWatcher devWatcher;
#ifdef DEBUG
void DumpApps();
void DumpEndpoints();

View File

@ -1,179 +1,199 @@
/*
* Copyright (c) 2003 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "PortDrivers.h"
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//------------------------------------------------------------------------------
MidiPortConsumer::MidiPortConsumer(int filedescriptor, const char *name = NULL)
: BMidiLocalConsumer(name),
fd(filedescriptor)
MidiPortConsumer::MidiPortConsumer(int fd_, const char* name = NULL)
: BMidiLocalConsumer(name)
{
};
fd = fd_;
}
//----------------------------
//------------------------------------------------------------------------------
void MidiPortConsumer::Data(uchar *data, size_t length, bool atomic, bigtime_t time)
void MidiPortConsumer::Data(
uchar* data, size_t length, bool atomic, bigtime_t time)
{
snooze_until(time - Latency(), B_SYSTEM_TIMEBASE);
if (write(fd, data, length) == -1)
perror("Error while sending data to Hardware ");
};
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
MidiPortProducer::MidiPortProducer(int filedescriptor, const char *name = NULL)
: BMidiLocalProducer(name),
fd(filedescriptor),
KeepRunning(true)
{
thread_id thread = spawn_thread(SpawnThread, "MidiDriversProducer", B_URGENT_PRIORITY, this);
if (thread >= 0)
perror("Error sending data to driver");
}
}
//------------------------------------------------------------------------------
MidiPortProducer::MidiPortProducer(int fd_, const char *name = NULL)
: BMidiLocalProducer(name)
{
fd = fd_;
keepRunning = true;
thread_id thread = spawn_thread(
SpawnThread, "MidiDriversProducer", B_URGENT_PRIORITY, this);
resume_thread(thread);
};
//----------------------------
MidiPortProducer::~MidiPortProducer(void)
{
KeepRunning = false;
}
//----------------------------
//------------------------------------------------------------------------------
int32 MidiPortProducer::SpawnThread(MidiPortProducer *producer)
MidiPortProducer::~MidiPortProducer()
{
return producer->GetData();
keepRunning = false;
}
//----------------------------
//------------------------------------------------------------------------------
int32 MidiPortProducer::GetData(void)
int32 MidiPortProducer::SpawnThread(void* data)
{
uchar newdata[3];
uchar *message;
while (KeepRunning)
return ((MidiPortProducer*) data)->GetData();
}
//------------------------------------------------------------------------------
int32 MidiPortProducer::GetData()
{
if (read(fd, newdata, 1) != 1)
uchar data[3];
while (keepRunning)
{
perror("Error while getting data ");
if (read(fd, data, 1) != 1)
{
perror("Error reading data from driver");
return B_ERROR;
}
switch(newdata[0] & 0xF0)
switch (data[0] & 0xF0)
{
case 0x80 : read(fd, newdata + 1, 2);
printf("Note OFF\n");
SprayData(newdata, 3);
case B_NOTE_OFF:
read(fd, data + 1, 2);
SprayNoteOff(data[0] & 0x0F, data[1], data[2]);
break;
case 0x90 : read(fd, newdata + 1, 2);
printf("Note ON\n");
SprayData(newdata, 3);
case B_NOTE_ON:
read(fd, data + 1, 2);
SprayNoteOn(data[0] & 0x0F, data[1], data[2]);
break;
case 0xA0 : read(fd, newdata + 1, 2);
printf("AfterTouch\n");
SprayData(newdata, 3);
case B_KEY_PRESSURE:
read(fd, data + 1, 2);
SprayKeyPressure(data[0] & 0x0F, data[1], data[2]);
break;
case 0xB0 : read(fd, newdata + 1, 2);
printf("Controler\n");
SprayData(newdata, 3);
case B_CONTROL_CHANGE:
read(fd, data + 1, 2);
SprayControlChange(data[0] & 0x0F, data[1], data[2]);
break;
case 0xC0 : read(fd, newdata + 1, 1);
printf("Program Change\n");
SprayData(newdata, 2);
case B_PROGRAM_CHANGE:
read(fd, data + 1, 1);
SprayProgramChange(data[0] & 0x0F, data[1]);
break;
case 0xD0 : read(fd, newdata + 1, 1);
printf("Channel Pressure\n");
SprayData(newdata, 2);
case B_CHANNEL_PRESSURE:
read(fd, data + 1, 1);
SprayChannelPressure(data[0] & 0x0F, data[1]);
break;
case 0xE0 : read(fd, newdata + 1, 2);
printf("Pitch Wheel\n");
SprayData(newdata, 3);
case B_PITCH_BEND:
read(fd, data + 1, 2);
SprayPitchBend(data[0] & 0x0F, data[1], data[2]);
break;
}
switch (newdata[0])
switch (data[0])
{
case 0xF0 : {
int32 index = 0;
message = new uchar[1000];
read(fd, newdata, 1);
while (newdata[0] != 0xF7)
case B_SYS_EX_START:
{
message[index++] = newdata[0];
read(fd, newdata, 1);
size_t msg_size = 4096;
uchar* msg = (uchar*) malloc(msg_size);
size_t count = 0;
while (read(fd, msg + count, 1) == 1)
{
// Realtime events may interleave System Exclusives. Any
// non-realtime status byte (not just 0xF7) ends a sysex.
if (msg[count] >= 0xF8)
{
SpraySystemRealTime(msg[count]);
}
printf("System Exclusive\n");
SpraySystemExclusive(message, index);
//Must we delete message after passing it to SpraySystemExclusive??
delete message;
else if (msg[count] >= 0xF0)
{
SpraySystemExclusive(msg, count - 1);
break;
}
else // a normal data byte
{
++count;
if (count == msg_size)
{
msg_size *= 2;
msg = (uchar*) realloc(msg, msg_size);
}
}
}
free(msg);
break;
case 0xF1 : read(fd, newdata + 1, 1); //TimeCode Value
printf("Quarter Frame Message\n");
SprayData(newdata, 2);
}
case B_TUNE_REQUEST:
case B_SYS_EX_END:
SpraySystemCommon(data[0], 0, 0);
break;
case 0xF2 : read(fd, newdata + 1, 2); //LSB, MSB
printf("Song Position Pointer\n");
SprayData(newdata, 3);
case B_MIDI_TIME_CODE:
case B_SONG_SELECT:
case B_CABLE_MESSAGE:
read(fd, data + 1, 1);
SpraySystemCommon(data[0], data[1], 0);
break;
case 0xF3 : read(fd, newdata + 1, 1); //Number
printf("Song Selection\n");
SprayData(newdata, 2);
case B_SONG_POSITION:
read(fd, data + 1, 2);
SpraySystemCommon(data[0], data[1], data[2]);
break;
case 0xF6 : printf("Tune Request\n");
SprayData(newdata, 1);
break;
case 0xF8 : printf("Timing Clock\n");
SprayData(newdata, 1);
break;
case 0xFA : printf("Start\n");
SprayData(newdata, 1);
break;
case 0xFB : printf("Continue\n");
SprayData(newdata, 1);
break;
case 0xFC : printf("Stop\n");
SprayData(newdata, 1);
break;
case 0xFE : printf("Active Sensing\n");
SprayData(newdata, 1);
break;
case 0xFF : read(fd, newdata + 1, 2); //Type, Size
message = new uchar[newdata[2] + 3];
message[0] = 0xFF;
message[1] = newdata[1];
message[2] = newdata[2];
read(fd, message + 3, message[2]);
printf("System Message\n");
SprayData(message, message[1] + 3);
//Must we delete message after passing it to SprayData??
delete message;
case B_TIMING_CLOCK:
case B_START:
case B_CONTINUE:
case B_STOP:
case B_ACTIVE_SENSING:
case B_SYSTEM_RESET:
SpraySystemRealTime(data[0]);
break;
}
}
return B_OK;
}
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//----------------------------------------------------------
//------------------------------------------------------------------------------

View File

@ -1,40 +1,56 @@
#ifndef _PORT_DRIVER_H
#define _PORT_DRIVER_H
/*
* Copyright (c) 2003 Matthijs Hollemans
* Copyright (c) 2003 Jerome Leveque
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef _PORT_DRIVERS_H
#define _PORT_DRIVERS_H
#include <MidiProducer.h>
#include <MidiConsumer.h>
//----------------------------------------------------------
class MidiPortConsumer : public BMidiLocalConsumer
{
public:
MidiPortConsumer(int filedescriptor, const char *name);
MidiPortConsumer(int fd, const char* name);
void Data(uchar *data, size_t length, bool atomic, bigtime_t time);
virtual void Data(uchar* data, size_t length, bool atomic, bigtime_t time);
private:
int fd;
};
//----------------------------------------------------------
class MidiPortProducer : public BMidiLocalProducer
{
public:
MidiPortProducer(int filedescriptor, const char *name);
MidiPortProducer(int fd, const char* name);
~MidiPortProducer(void);
static int32 SpawnThread(MidiPortProducer *producer);
int32 GetData(void);
private:
static int32 SpawnThread(void* data);
int fd;
bool KeepRunning;
bool keepRunning;
};
//----------------------------------------------------------
#endif
#endif // _PORT_DRIVERS_H

View File

@ -3,3 +3,58 @@ resource app_signature "application/x-vnd.OpenBeOS.midi-server";
resource app_flags 0x00000004; // BACKGROUND_APP | SINGLE_LAUNCH
resource(10, "bus_large") #'ICON' array
{
$"FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFF0000000000000000000000000000FFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFF00000000000A0A0A0A0A0A0A0A0000000000FFFFFFFFFFFFFF"
$"FFFFFFFFFFFF000000000A0A0A0A0A0A0A0A0A0A0A0A00000000FFFFFFFFFFFF"
$"FFFFFFFFFF0000000A0A0A0A0A0A0A00000A0A0A0A0A0A0A000000FFFFFFFFFF"
$"FFFFFFFF0000000A0A0A0A0A0A0A000000000A0A0A0A0A0A0A000000FFFFFFFF"
$"FFFFFF0000000C0C0C0C0C0C0C0C000000000C0C0C0C0C0C0C0C000000FFFFFF"
$"FFFF0000000C0C0C00000C0C0C0C0C00000C0C0C0C0C00000C0C0C000000FFFF"
$"FFFF00000C0C0C000000000C0C0C0C0C0C0C0C0C0C000000000C0C0C0000FFFF"
$"FF0000000C0C0C000000000C0C0C0C0C0C0C0C0C0C000000000C0C0C000000FF"
$"FF00000E0E0E0E0E00000E0E0E0E0E0E0E0E0E0E0E0E00000E0E0E0E0E0000FF"
$"FF00000E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0000FF"
$"00000E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0000"
$"00000E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0000"
$"0000101010000010101010101010101010101010101010101000001010100000"
$"0000101000000000101010101010101010101010101010100000000010100000"
$"0000101000000000101010101010101010101010101010100000000010100000"
$"0000101010000010101010101010101010101010101010101000001010100000"
$"0000121212121212121212121212121212121212121212121212121212120000"
$"0000121212121212121212121212121212121212121212121212121212120000"
$"FF000012121212121212121212121212121212121212121212121212120000FF"
$"FF000012121212121212121212121212121212121212121212121212120000FF"
$"FF000000141414141414141414141414141414141414141414141414000000FF"
$"FFFF00001414141414141414141414141414141414141414141414140000FFFF"
$"FFFF00000014141414141414141414141414141414141414141414000000FFFF"
$"FFFFFF0000001414141414141414141414141414141414141414000000FFFFFF"
$"FFFFFFFF000000161616161616161616161616161616161616000000FFFFFFFF"
$"FFFFFFFFFF00000016161616161616161616161616161616000000FFFFFFFFFF"
$"FFFFFFFFFFFF0000000016161616161616161616161600000000FFFFFFFFFFFF"
$"FFFFFFFFFFFFFF000000000016161616161616160000000000FFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFF0000000000000000000000000000FFFFFFFFFFFFFFFFFF"
$"FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
};
resource(11, "bus_small") #'MICN' array
{
$"FFFFFFFFFFFF00000000FFFFFFFFFFFF"
$"FFFFFFFF00000A0A0A0A0000FFFFFFFF"
$"FFFFFF000A0A0A00000A0A0A00FFFFFF"
$"FFFF000C0C0C0C00000C0C0C0C00FFFF"
$"FF000C00000C0C0C0C0C0C00000C00FF"
$"FF000E00000E0E0E0E0E0E00000E00FF"
$"000E0E0E0E0E0E0E0E0E0E0E0E0E0E00"
$"00100000101010101010101000001000"
$"00100000101010101010101000001000"
$"00121212121212121212121212121200"
$"FF0012121212121212121212121200FF"
$"FF0014141414141414141414141400FF"
$"FFFF001414141414141414141400FFFF"
$"FFFFFF00161616161616161600FFFFFF"
$"FFFFFFFF0000161616160000FFFFFFFF"
$"FFFFFFFFFFFF00000000FFFFFFFFFFFF"
};