1/*
2 * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27#define USE_ERROR
28#define USE_TRACE
29
30#include "PlatformMidi.h"
31
32#include <stdlib.h>
33
34char* GetInternalErrorStr(INT32 err) {
35    switch (err) {
36    case MIDI_SUCCESS:          return "";
37    case MIDI_NOT_SUPPORTED:    return "feature not supported";
38    case MIDI_INVALID_DEVICEID: return "invalid device ID";
39    case MIDI_INVALID_HANDLE:   return "internal error: invalid handle";
40    case MIDI_OUT_OF_MEMORY:    return "out of memory";
41    }
42    return NULL;
43}
44
45/*
46 * internal implementation for getting error string
47 */
48char* MIDI_IN_InternalGetErrorString(INT32 err) {
49    char* result = GetInternalErrorStr(err);
50
51#if USE_PLATFORM_MIDI_IN == TRUE
52    if (!result) {
53        result = MIDI_IN_GetErrorStr(err);
54    }
55#endif
56    if (!result) {
57        result = GetInternalErrorStr(MIDI_NOT_SUPPORTED);
58    }
59    return result;
60}
61
62/*
63 * internal implementation for getting error string
64 */
65char* MIDI_OUT_InternalGetErrorString(INT32 err) {
66    char* result = GetInternalErrorStr(err);
67
68#if USE_PLATFORM_MIDI_OUT == TRUE
69    if (!result) {
70        result = MIDI_OUT_GetErrorStr(err);
71    }
72#endif
73    if (!result) {
74        result = GetInternalErrorStr(MIDI_NOT_SUPPORTED);
75    }
76    return result;
77}
78
79
80#if USE_MIDI_QUEUE == TRUE
81
82// MessageQueue implementation
83
84MidiMessageQueue* MIDI_CreateQueue(int capacity) {
85    MidiMessageQueue* queue = (MidiMessageQueue*) malloc(sizeof(MidiMessageQueue) + ((capacity-1) * sizeof(MidiMessage)));
86    if (queue) {
87        TRACE0("MIDI_CreateQueue\n");
88        queue->lock = MIDI_CreateLock();
89        queue->capacity = capacity;
90        queue->size = 0;
91        queue->readIndex = 0;
92        queue->writeIndex = 0;
93    }
94    return queue;
95}
96
97void MIDI_DestroyQueue(MidiMessageQueue* queue) {
98    if (queue) {
99        void* lock = queue->lock;
100        MIDI_Lock(lock);
101        free(queue);
102        MIDI_Unlock(lock);
103        MIDI_DestroyLock(lock);
104        TRACE0("MIDI_DestroyQueue\n");
105    }
106}
107
108// if overwrite is true, oldest messages will be overwritten when the queue is full
109// returns true, if message has been added
110int MIDI_QueueAddShort(MidiMessageQueue* queue, UINT32 packedMsg, INT64 timestamp, int overwrite) {
111    if (queue) {
112        MIDI_Lock(queue->lock);
113        if (queue->size == queue->capacity) {
114            TRACE0("MIDI_QueueAddShort: overflow\n");
115            if (!overwrite || queue->queue[queue->writeIndex].locked) {
116                return FALSE; // failed
117            }
118            // adjust overwritten readIndex
119            queue->readIndex = (queue->readIndex+1) % queue->capacity;
120        } else {
121            queue->size++;
122        }
123        TRACE2("MIDI_QueueAddShort. index=%d, size=%d\n", queue->writeIndex, queue->size);
124        queue->queue[queue->writeIndex].type = SHORT_MESSAGE;
125        queue->queue[queue->writeIndex].data.s.packedMsg = packedMsg;
126        queue->queue[queue->writeIndex].timestamp = timestamp;
127        queue->writeIndex = (queue->writeIndex+1) % queue->capacity;
128        MIDI_Unlock(queue->lock);
129        return TRUE;
130    }
131    return FALSE;
132}
133
134int MIDI_QueueAddLong(MidiMessageQueue* queue, UBYTE* data, UINT32 size,
135                      INT32 sysexIndex, INT64 timestamp, int overwrite) {
136    if (queue) {
137        MIDI_Lock(queue->lock);
138        if (queue->size == queue->capacity) {
139            TRACE0("MIDI_QueueAddLong: overflow\n");
140            if (!overwrite || queue->queue[queue->writeIndex].locked) {
141                return FALSE; // failed
142            }
143            // adjust overwritten readIndex
144            queue->readIndex = (queue->readIndex+1) % queue->capacity;
145        } else {
146            queue->size++;
147        }
148        TRACE2("MIDI_QueueAddLong. index=%d, size=%d\n", queue->writeIndex, queue->size);
149        //fprintf(stdout, "MIDI_QueueAddLong sysex-index %d\n", sysexIndex); fflush(stdout);
150        queue->queue[queue->writeIndex].type = LONG_MESSAGE;
151        queue->queue[queue->writeIndex].data.l.size = size;
152        queue->queue[queue->writeIndex].data.l.data = data;
153        queue->queue[queue->writeIndex].data.l.index = sysexIndex;
154        queue->queue[queue->writeIndex].timestamp = timestamp;
155        queue->writeIndex = (queue->writeIndex+1) % queue->capacity;
156        MIDI_Unlock(queue->lock);
157        return TRUE;
158    }
159    return FALSE;
160}
161
162// returns NULL if no messages in queue.
163MidiMessage* MIDI_QueueRead(MidiMessageQueue* queue) {
164    MidiMessage* msg = NULL;
165    if (queue) {
166        MIDI_Lock(queue->lock);
167        if (queue->size > 0) {
168            msg = &(queue->queue[queue->readIndex]);
169            TRACE2("MIDI_QueueRead. index=%d, size=%d\n", queue->readIndex, queue->size);
170            msg->locked = TRUE;
171        }
172        MIDI_Unlock(queue->lock);
173    }
174    return msg;
175}
176
177void MIDI_QueueRemove(MidiMessageQueue* queue, INT32 onlyLocked) {
178    if (queue) {
179        MIDI_Lock(queue->lock);
180        if (queue->size > 0) {
181            MidiMessage* msg = &(queue->queue[queue->readIndex]);
182            if (!onlyLocked || msg->locked) {
183                TRACE2("MIDI_QueueRemove. index=%d, size=%d\n", queue->readIndex, queue->size);
184                queue->readIndex = (queue->readIndex+1) % queue->capacity;
185                queue->size--;
186            }
187            msg->locked = FALSE;
188        }
189        MIDI_Unlock(queue->lock);
190    }
191}
192
193void MIDI_QueueClear(MidiMessageQueue* queue) {
194    if (queue) {
195        MIDI_Lock(queue->lock);
196        queue->size = 0;
197        queue->readIndex = 0;
198        queue->writeIndex = 0;
199        MIDI_Unlock(queue->lock);
200    }
201}
202
203#endif
204