149fa1748Smahlzeit/*
277f87987SJérôme Duval * Copyright 2006, Haiku.
377f87987SJérôme Duval *
477f87987SJérôme Duval * Copyright (c) 2002-2003 Matthijs Hollemans
577f87987SJérôme Duval * Copyright (c) 2002 Jerome Leveque
64810cdcdSJérôme Duval * Distributed under the terms of the MIT License.
7f9493271Sjerl *
84810cdcdSJérôme Duval * Authors:
94810cdcdSJérôme Duval *		Matthijs Hollemans
104810cdcdSJérôme Duval *		J��r��me Leveque
11f9493271Sjerl */
12f9493271Sjerl
134810cdcdSJérôme Duval#include <MidiPort.h>
1449fa1748Smahlzeit#include <MidiProducer.h>
15f9493271Sjerl#include <MidiRoster.h>
1649fa1748Smahlzeit#include <stdlib.h>
17f9493271Sjerl
1849fa1748Smahlzeit#include "debug.h"
1949fa1748Smahlzeit#include "MidiGlue.h"
20f9493271Sjerl
2132ed9cc8Smahlzeitusing namespace BPrivate;
2232ed9cc8Smahlzeit
23f9493271Sjerl
24f9493271SjerlBMidiPort::BMidiPort(const char* name)
25f9493271Sjerl{
264810cdcdSJérôme Duval	fPortName = NULL;
274810cdcdSJérôme Duval	fDevices  = new BList;
284810cdcdSJérôme Duval	fStatus   = B_ERROR;
2949fa1748Smahlzeit
304810cdcdSJérôme Duval	fLocalSource = new BMidiLocalProducer("MidiPortGlue(out)");
314810cdcdSJérôme Duval	fLocalSink   = new BMidiPortGlue(this, "MidiPortGlue(in)");
32beb0419dSJérôme Duval	fLocalSource->Register();
33beb0419dSJérôme Duval	fLocalSink->Register();
3449fa1748Smahlzeit
354810cdcdSJérôme Duval	fRemoteSource = NULL;
364810cdcdSJérôme Duval	fRemoteSink   = NULL;
37f9493271Sjerl
38f9493271Sjerl	ScanDevices();
3949fa1748Smahlzeit
4049fa1748Smahlzeit	if (name != NULL)
4149fa1748Smahlzeit		Open(name);
42f9493271Sjerl}
43f9493271Sjerl
44f9493271Sjerl
45f9493271SjerlBMidiPort::~BMidiPort()
46f9493271Sjerl{
47f9493271Sjerl	Close();
4849fa1748Smahlzeit
4949fa1748Smahlzeit	EmptyDeviceList();
504810cdcdSJérôme Duval	delete fDevices;
5149fa1748Smahlzeit
52beb0419dSJérôme Duval	fLocalSource->Unregister();
53beb0419dSJérôme Duval	fLocalSink->Unregister();
544810cdcdSJérôme Duval	fLocalSource->Release();
554810cdcdSJérôme Duval	fLocalSink->Release();
56f9493271Sjerl}
57f9493271Sjerl
58f9493271Sjerl
594810cdcdSJérôme Duvalstatus_t
604810cdcdSJérôme DuvalBMidiPort::InitCheck() const
61f9493271Sjerl{
624810cdcdSJérôme Duval	return fStatus;
63f9493271Sjerl}
64f9493271Sjerl
65f9493271Sjerl
664810cdcdSJérôme Duvalstatus_t
674810cdcdSJérôme DuvalBMidiPort::Open(const char* name)
68f9493271Sjerl{
694810cdcdSJérôme Duval	fStatus = B_ERROR;
70f9493271Sjerl
714810cdcdSJérôme Duval	if (name != NULL) {
7249fa1748Smahlzeit		Close();
7349fa1748Smahlzeit
744810cdcdSJérôme Duval		for (int32 t = 0; t < fDevices->CountItems(); ++t) {
75b2e8d962SStefano Ceccherini			BMidiEndpoint* endp = (BMidiEndpoint*)fDevices->ItemAt(t);
764810cdcdSJérôme Duval			if (strcmp(name, endp->Name()) != 0)
774810cdcdSJérôme Duval				continue;
784810cdcdSJérôme Duval			if (!endp->IsValid())  // still exists?
794810cdcdSJérôme Duval				continue;
804810cdcdSJérôme Duval			if (endp->IsProducer()) {
814810cdcdSJérôme Duval				if (fRemoteSource == NULL)
82b2e8d962SStefano Ceccherini					fRemoteSource = (BMidiProducer*)endp;
834810cdcdSJérôme Duval			} else {
844810cdcdSJérôme Duval				if (fRemoteSink == NULL) {
85b2e8d962SStefano Ceccherini					fRemoteSink = (BMidiConsumer*)endp;
864810cdcdSJérôme Duval					fLocalSource->Connect(fRemoteSink);
8749fa1748Smahlzeit				}
88f9493271Sjerl			}
89f9493271Sjerl		}
9049fa1748Smahlzeit
914810cdcdSJérôme Duval		if (fRemoteSource != NULL) {
924810cdcdSJérôme Duval			fPortName = strdup(fRemoteSource->Name());
934810cdcdSJérôme Duval			fStatus = B_OK;
944810cdcdSJérôme Duval		} else if (fRemoteSink != NULL) {
954810cdcdSJérôme Duval			fPortName = strdup(fRemoteSink->Name());
964810cdcdSJérôme Duval			fStatus = B_OK;
97f9493271Sjerl		}
98f9493271Sjerl	}
9949fa1748Smahlzeit
1004810cdcdSJérôme Duval	return fStatus;
101f9493271Sjerl}
102f9493271Sjerl
103f9493271Sjerl
1044810cdcdSJérôme Duvalvoid
1054810cdcdSJérôme DuvalBMidiPort::Close()
106f9493271Sjerl{
1074810cdcdSJérôme Duval	if (fRemoteSource != NULL) {
1084810cdcdSJérôme Duval		fRemoteSource->Disconnect(fLocalSink);
1094810cdcdSJérôme Duval		fRemoteSource = NULL;
110f9493271Sjerl	}
11149fa1748Smahlzeit
1124810cdcdSJérôme Duval	if (fRemoteSink != NULL) {
1134810cdcdSJérôme Duval		fLocalSource->Disconnect(fRemoteSink);
1144810cdcdSJérôme Duval		fRemoteSink = NULL;
11549fa1748Smahlzeit	}
11649fa1748Smahlzeit
1174810cdcdSJérôme Duval	if (fPortName != NULL) {
1184810cdcdSJérôme Duval		free(fPortName);
1194810cdcdSJérôme Duval		fPortName = NULL;
120f9493271Sjerl	}
121f9493271Sjerl}
122f9493271Sjerl
123f9493271Sjerl
1244810cdcdSJérôme Duvalconst char*
1254810cdcdSJérôme DuvalBMidiPort::PortName() const
126f9493271Sjerl{
1274810cdcdSJérôme Duval	return fPortName;
128f9493271Sjerl}
129f9493271Sjerl
130f9493271Sjerl
1314810cdcdSJérôme Duvalvoid
1324810cdcdSJérôme DuvalBMidiPort::NoteOff(
133f9493271Sjerl	uchar channel, uchar note, uchar velocity, uint32 time)
134f9493271Sjerl{
1354810cdcdSJérôme Duval	fLocalSource->SprayNoteOff(channel - 1, note, velocity, MAKE_BIGTIME(time));
136f9493271Sjerl}
137f9493271Sjerl
138f9493271Sjerl
1394810cdcdSJérôme Duvalvoid
1404810cdcdSJérôme DuvalBMidiPort::NoteOn(
141f9493271Sjerl	uchar channel, uchar note, uchar velocity, uint32 time)
142f9493271Sjerl{
1434810cdcdSJérôme Duval	fLocalSource->SprayNoteOn(channel - 1, note, velocity, MAKE_BIGTIME(time));
144f9493271Sjerl}
145f9493271Sjerl
146f9493271Sjerl
1474810cdcdSJérôme Duvalvoid
1484810cdcdSJérôme DuvalBMidiPort::KeyPressure(
149f9493271Sjerl	uchar channel, uchar note, uchar pressure, uint32 time)
150f9493271Sjerl{
1514810cdcdSJérôme Duval	fLocalSource->SprayKeyPressure(
15249fa1748Smahlzeit		channel - 1, note, pressure, MAKE_BIGTIME(time));
153f9493271Sjerl}
154f9493271Sjerl
155f9493271Sjerl
1564810cdcdSJérôme Duvalvoid
1574810cdcdSJérôme DuvalBMidiPort::ControlChange(
158f9493271Sjerl	uchar channel, uchar controlNumber, uchar controlValue, uint32 time)
159f9493271Sjerl{
1604810cdcdSJérôme Duval	fLocalSource->SprayControlChange(
16149fa1748Smahlzeit		channel - 1, controlNumber, controlValue, MAKE_BIGTIME(time));
162f9493271Sjerl}
163f9493271Sjerl
164f9493271Sjerl
1654810cdcdSJérôme Duvalvoid
1664810cdcdSJérôme DuvalBMidiPort::ProgramChange(
167f9493271Sjerl	uchar channel, uchar programNumber, uint32 time)
168f9493271Sjerl{
1694810cdcdSJérôme Duval	fLocalSource->SprayProgramChange(
17049fa1748Smahlzeit		channel - 1, programNumber, MAKE_BIGTIME(time));
171f9493271Sjerl}
172f9493271Sjerl
173f9493271Sjerl
1744810cdcdSJérôme Duvalvoid
1754810cdcdSJérôme DuvalBMidiPort::ChannelPressure(uchar channel, uchar pressure, uint32 time)
176f9493271Sjerl{
1774810cdcdSJérôme Duval	fLocalSource->SprayChannelPressure(
17849fa1748Smahlzeit		channel - 1, pressure, MAKE_BIGTIME(time));
179f9493271Sjerl}
180f9493271Sjerl
181f9493271Sjerl
1824810cdcdSJérôme Duvalvoid
1834810cdcdSJérôme DuvalBMidiPort::PitchBend(uchar channel, uchar lsb, uchar msb, uint32 time)
184f9493271Sjerl{
1854810cdcdSJérôme Duval	fLocalSource->SprayPitchBend(channel - 1, lsb, msb, MAKE_BIGTIME(time));
186f9493271Sjerl}
187f9493271Sjerl
188f9493271Sjerl
1894810cdcdSJérôme Duvalvoid
1904810cdcdSJérôme DuvalBMidiPort::SystemExclusive(void* data, size_t length, uint32 time)
191f9493271Sjerl{
1924810cdcdSJérôme Duval	fLocalSource->SpraySystemExclusive(data, length, MAKE_BIGTIME(time));
193f9493271Sjerl}
194f9493271Sjerl
195f9493271Sjerl
1964810cdcdSJérôme Duvalvoid
1974810cdcdSJérôme DuvalBMidiPort::SystemCommon(
198f9493271Sjerl	uchar status, uchar data1, uchar data2, uint32 time)
199f9493271Sjerl{
2004810cdcdSJérôme Duval	fLocalSource->SpraySystemCommon(status, data1, data2, MAKE_BIGTIME(time));
201f9493271Sjerl}
202f9493271Sjerl
203f9493271Sjerl
2044810cdcdSJérôme Duvalvoid
2054810cdcdSJérôme DuvalBMidiPort::SystemRealTime(uchar status, uint32 time)
206f9493271Sjerl{
2074810cdcdSJérôme Duval	fLocalSource->SpraySystemRealTime(status, MAKE_BIGTIME(time));
208f9493271Sjerl}
209f9493271Sjerl
210f9493271Sjerl
2114810cdcdSJérôme Duvalstatus_t
2124810cdcdSJérôme DuvalBMidiPort::Start()
213f9493271Sjerl{
21449fa1748Smahlzeit	status_t err = super::Start();
21549fa1748Smahlzeit
2164810cdcdSJérôme Duval	if ((err == B_OK) && (fRemoteSource != NULL)) {
2174810cdcdSJérôme Duval		return fRemoteSource->Connect(fLocalSink);
21849fa1748Smahlzeit	}
21949fa1748Smahlzeit
22049fa1748Smahlzeit	return err;
221f9493271Sjerl}
222f9493271Sjerl
223f9493271Sjerl
2244810cdcdSJérôme Duvalvoid
2254810cdcdSJérôme DuvalBMidiPort::Stop()
226f9493271Sjerl{
2274810cdcdSJérôme Duval	if (fRemoteSource != NULL) {
2284810cdcdSJérôme Duval		fRemoteSource->Disconnect(fLocalSink);
229f9493271Sjerl	}
23049fa1748Smahlzeit
23149fa1748Smahlzeit	super::Stop();
232f9493271Sjerl}
233f9493271Sjerl
234f9493271Sjerl
2354810cdcdSJérôme Duvalint32
2364810cdcdSJérôme DuvalBMidiPort::CountDevices()
237f9493271Sjerl{
2384810cdcdSJérôme Duval	return fDevices->CountItems();
239f9493271Sjerl}
240f9493271Sjerl
241f9493271Sjerl
2424810cdcdSJérôme Duvalstatus_t
2434810cdcdSJérôme DuvalBMidiPort::GetDeviceName(int32 n, char* name, size_t bufSize)
244f9493271Sjerl{
245b2e8d962SStefano Ceccherini	BMidiEndpoint* endp = (BMidiEndpoint*)fDevices->ItemAt(n);
24649fa1748Smahlzeit	if (endp == NULL)
247f9493271Sjerl		return B_BAD_VALUE;
24849fa1748Smahlzeit
24949fa1748Smahlzeit	size_t size = strlen(endp->Name());
25049fa1748Smahlzeit	if (size >= bufSize)
251f9493271Sjerl		return B_NAME_TOO_LONG;
25249fa1748Smahlzeit
25349fa1748Smahlzeit	strcpy(name, endp->Name());
25449fa1748Smahlzeit	return B_OK;
255f9493271Sjerl}
256f9493271Sjerl
257f9493271Sjerl
258f9493271Sjerlvoid BMidiPort::_ReservedMidiPort1() { }
259f9493271Sjerlvoid BMidiPort::_ReservedMidiPort2() { }
260f9493271Sjerlvoid BMidiPort::_ReservedMidiPort3() { }
261f9493271Sjerl
262f9493271Sjerl
2634810cdcdSJérôme Duvalvoid
2644810cdcdSJérôme DuvalBMidiPort::Run()
265f9493271Sjerl{
2664810cdcdSJérôme Duval	while (KeepRunning())
267f9493271Sjerl		snooze(50000);
268f9493271Sjerl}
269f9493271Sjerl
270f9493271Sjerl
2714810cdcdSJérôme Duvalvoid
2724810cdcdSJérôme DuvalBMidiPort::ScanDevices()
273f9493271Sjerl{
27449fa1748Smahlzeit	EmptyDeviceList();
27549fa1748Smahlzeit
27649fa1748Smahlzeit	int32 id = 0;
27749fa1748Smahlzeit	BMidiEndpoint* endp;
27849fa1748Smahlzeit
2794810cdcdSJérôme Duval	while ((endp = BMidiRoster::NextEndpoint(&id)) != NULL) {
28049fa1748Smahlzeit		// Each hardware port has two endpoints associated with it, a consumer
28149fa1748Smahlzeit		// and a producer. Both have the same name, so we add only one of them.
28249fa1748Smahlzeit
28349fa1748Smahlzeit		bool addItem = true;
2844810cdcdSJérôme Duval		for (int32 t = 0; t < fDevices->CountItems(); ++t) {
285b2e8d962SStefano Ceccherini			BMidiEndpoint* other = (BMidiEndpoint*)fDevices->ItemAt(t);
2864810cdcdSJérôme Duval			if (strcmp(endp->Name(), other->Name()) == 0) {
28749fa1748Smahlzeit				addItem = false;
28849fa1748Smahlzeit				break;
28949fa1748Smahlzeit			}
29049fa1748Smahlzeit		}
29149fa1748Smahlzeit
2924810cdcdSJérôme Duval		if (addItem) {
2934810cdcdSJérôme Duval			fDevices->AddItem(endp);
2944810cdcdSJérôme Duval		} else {
29549fa1748Smahlzeit			endp->Release();
296f9493271Sjerl		}
297f9493271Sjerl	}
298f9493271Sjerl}
299f9493271Sjerl
300f9493271Sjerl
3014810cdcdSJérôme Duvalvoid
3024810cdcdSJérôme DuvalBMidiPort::EmptyDeviceList()
30349fa1748Smahlzeit{
3044810cdcdSJérôme Duval	for (int32 t = 0; t < fDevices->CountItems(); ++t)
305b2e8d962SStefano Ceccherini		((BMidiEndpoint*)fDevices->ItemAt(t))->Release();
30649fa1748Smahlzeit
3074810cdcdSJérôme Duval	fDevices->MakeEmpty();
30849fa1748Smahlzeit}
30949fa1748Smahlzeit
310