OSDN Git Service

[VM][OSD] Add upstream devices/OSD updates.
[csp-qt/common_source_project-fm7.git] / source / src / win32 / osd_midi.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2022.07.03-
6
7         [ win32 midi ]
8 */
9
10 #include "osd.h"
11 #include "../fifo.h"
12
13 CRITICAL_SECTION send_cs;
14 CRITICAL_SECTION recv_cs;
15
16 unsigned __stdcall midi_thread(void *lpx)
17 {
18         volatile midi_thread_params_t *p = (midi_thread_params_t *)lpx;
19         HMIDIOUT hMidi = NULL;
20         MMRESULT result = midiOutOpen(&hMidi, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL);
21         
22         while(!p->terminate) {
23                 while(true) {
24                         uint8_t buffer[128];
25                         int length = 0;
26                         
27                         EnterCriticalSection(&send_cs);
28                         if(!p->send_buffer->empty()) {
29                                 uint8_t msg = p->send_buffer->read_not_remove(0);
30                                 
31                                 switch(msg & 0xf0) {
32                                 case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0:
33                                         length = 3;
34                                         break;
35                                 case 0xc0:
36                                 case 0xd0:
37                                         length = 2;
38                                         break;
39                                 case 0xf0:
40                                         switch(msg) {
41                                         case 0xf0:
42                                                 // system exclusive
43                                                 for(int i = 1; i < p->send_buffer->count(); i++) {
44                                                         if(p->send_buffer->read_not_remove(i) == 0xf7) {
45                                                                 length = i + 1;
46                                                                 break;
47                                                         }
48                                                 }
49                                                 break;
50                                         case 0xf1: case 0xf3:
51                                                 length = 2;
52                                                 break;
53                                         case 0xf2:
54                                                 length = 3;
55                                                 break;
56                                         case 0xf6: case 0xf8: case 0xfa: case 0xfb: case 0xfc: case 0xfe: case 0xff:
57                                                 length = 1;
58                                                 break;
59                                         default:
60                                                 // undefined msg
61                                                 p->send_buffer->read();
62                                                 break;
63                                         }
64                                         break;
65                                 default:
66                                         // invalid msg
67                                         p->send_buffer->read();
68                                         break;
69                                 }
70                                 if(p->send_buffer->count() >= length) {
71                                         for(int i = 0; i < length; i++) {
72                                                 buffer[i] = p->send_buffer->read();
73                                         }
74                                 } else {
75                                         length = 0;
76                                 }
77                         }
78                         LeaveCriticalSection(&send_cs);
79                         
80                         if(length > 0) {
81                                 if(result == MMSYSERR_NOERROR) {
82                                         if(buffer[0] == 0xf0) {
83                                                 // system exclusive
84                                                 MIDIHDR mhMidi;
85                                                 
86                                                 ZeroMemory(&mhMidi, sizeof(mhMidi));
87                                                 mhMidi.lpData = (LPSTR)buffer;
88                                                 mhMidi.dwBufferLength = length;
89                                                 mhMidi.dwBytesRecorded = length;
90                                                 midiOutPrepareHeader(hMidi, &mhMidi, sizeof(mhMidi));
91                                                 midiOutLongMsg(hMidi, &mhMidi, sizeof(mhMidi));
92                                                 while(!(mhMidi.dwFlags & MHDR_DONE)) {
93                                                         Sleep(10);
94                                                 }
95                                                 midiOutUnprepareHeader(hMidi, &mhMidi, sizeof(mhMidi));
96                                         } else {
97                                                 union UNION_MIDI_DATA {
98                                                         DWORD msg;
99                                                         BYTE data[4];
100                                                 };
101                                                 UNION_MIDI_DATA out;
102                                                 
103                                                 for(int i = 0; i < 4; i++) {
104                                                         out.data[i] = (i < length) ? buffer[i] : 0;
105                                                 }
106                                                 midiOutShortMsg(hMidi,out.msg);
107                                         }
108                                 }
109                         } else {
110                                 break;
111                         }
112                 }
113                 Sleep(10);
114         }
115         if(result == MMSYSERR_NOERROR) {
116                 midiOutClose(hMidi);
117         }
118         _endthreadex(0);
119         return 0;
120 }
121
122 void OSD::initialize_midi()
123 {
124         midi_thread_params.send_buffer = new FIFO(1024);
125         midi_thread_params.recv_buffer = new FIFO(1024);
126         midi_thread_params.terminate = false;
127         
128         InitializeCriticalSection(&send_cs);
129         InitializeCriticalSection(&recv_cs);
130         hMidiThread = (HANDLE)_beginthreadex(NULL, 0, midi_thread, &midi_thread_params, 0, NULL);
131 }
132
133 void OSD::release_midi()
134 {
135         if(hMidiThread) {
136                 midi_thread_params.terminate = true;
137                 WaitForSingleObject(hMidiThread, INFINITE);
138                 hMidiThread = NULL;
139         }
140         DeleteCriticalSection(&send_cs);
141         DeleteCriticalSection(&recv_cs);
142         
143         midi_thread_params.send_buffer->release();
144         delete midi_thread_params.send_buffer;
145         midi_thread_params.send_buffer = NULL;
146         midi_thread_params.recv_buffer->release();
147         delete midi_thread_params.recv_buffer;
148         midi_thread_params.recv_buffer = NULL;
149 }
150
151 void OSD::send_to_midi(uint8_t data)
152 {
153         EnterCriticalSection(&send_cs);
154         midi_thread_params.send_buffer->write(data);
155         LeaveCriticalSection(&send_cs);
156 }
157
158 bool OSD::recv_from_midi(uint8_t *data)
159 {
160         bool result = false;
161         EnterCriticalSection(&recv_cs);
162         if(!midi_thread_params.recv_buffer->empty()) {
163                 *data = (uint8_t)midi_thread_params.recv_buffer->read();
164                 result = true;
165         }
166         LeaveCriticalSection(&recv_cs);
167         return result;
168 }