11#include < iostream>
2+ #include < chrono>
3+
24#include < stdint-gcc.h>
35#include < unistd.h>
46#include < stdint.h>
5- # include < chrono >
7+
68#include < signal.h>
9+ #include < stdio.h>
710
811#include " libusb/libusb.h"
912#include " midifile/midifile.h"
1316#define DEFAULT_INTERVAL_USEC 10000
1417
1518#define DURATION_MAX -1
16- #define NOTE_STOP 128
19+ #define NOTE_STOP - 1
1720
1821using namespace std ;
1922
@@ -80,7 +83,7 @@ void SteamController_Close(SteamControllerInfos* controller){
8083}
8184
8285
83- int SteamController_PlayNote (SteamControllerInfos* controller, int haptic, unsigned int note,double duration = DURATION_MAX){
86+ int SteamController_PlayNote (SteamControllerInfos* controller, int haptic, int note,double duration = DURATION_MAX){
8487 double midiFrequency[128] = {8.1758, 8.66196, 9.17702, 9.72272, 10.3009, 10.9134, 11.5623, 12.2499, 12.9783, 13.75, 14.5676, 15.4339, 16.3516, 17.3239, 18.354, 19.4454, 20.6017, 21.8268, 23.1247, 24.4997, 25.9565, 27.5, 29.1352, 30.8677, 32.7032, 34.6478, 36.7081, 38.8909, 41.2034, 43.6535, 46.2493, 48.9994, 51.9131, 55, 58.2705, 61.7354, 65.4064, 69.2957, 73.4162, 77.7817, 82.4069, 87.3071, 92.4986, 97.9989, 103.826, 110, 116.541, 123.471, 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220, 233.082, 246.942, 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440, 466.164, 493.883, 523.251, 554.365, 587.33, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880, 932.328, 987.767, 1046.5, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760, 1864.66, 1975.53, 2093, 2217.46, 2349.32, 2489.02, 2637.02, 2793.83, 2959.96, 3135.96, 3322.44, 3520, 3729.31, 3951.07, 4186.01, 4434.92, 4698.64, 4978.03, 5274.04, 5587.65, 5919.91, 6271.93, 6644.88, 7040, 7458.62, 7902.13, 8372.02, 8869.84, 9397.27, 9956.06, 10548.1, 11175.3, 11839.8, 12543.9};
8588
8689 unsigned char dataBlob[64 ] = {0x8f ,
@@ -97,7 +100,7 @@ int SteamController_PlayNote(SteamControllerInfos* controller, int haptic, unsig
97100 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
98101 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
99102
100- if (note > = NOTE_STOP){
103+ if (note = = NOTE_STOP){
101104 note = 0 ;
102105 duration = 0.0 ;
103106 }
@@ -136,17 +139,9 @@ float timeElapsedSince(std::chrono::steady_clock::time_point tOrigin){
136139 return time_span.count ();
137140}
138141
139- bool isThisEventMaskingPreviousEvent (MidiFileEvent_t currentEvent, MidiFileEvent_t previousEvent){
140- return (MidiFileEvent_isNoteEndEvent (currentEvent)
141- && MidiFileEvent_isNoteStartEvent (previousEvent)
142- && MidiFileNoteEndEvent_getChannel (currentEvent) == MidiFileNoteStartEvent_getChannel (previousEvent)
143- && MidiFileEvent_getTick (currentEvent) == MidiFileEvent_getTick (previousEvent));
144- }
145-
146142
147-
148- void displayCurrentNote (int channel, unsigned int note){
149- static unsigned int notePerChannel[CHANNEL_COUNT] = {NOTE_STOP, NOTE_STOP};
143+ void displayPlayedNotes (int channel, int8_t note){
144+ static int8_t notePerChannel[CHANNEL_COUNT] = {NOTE_STOP, NOTE_STOP};
150145 const char * textPerChannel[CHANNEL_COUNT] = {" LEFT haptic : " ," , RIGHT haptic : " };
151146 const char * noteBaseNameArray[12 ] = {" C" ," C#" ," D" ," D#" ," E" ," F" ," F#" ," G" ," G#" ," A" ," A#" ," B" };
152147
@@ -159,7 +154,7 @@ void displayCurrentNote(int channel, unsigned int note){
159154 cout << textPerChannel[i];
160155
161156 // Write empty string
162- if (notePerChannel[i] > = NOTE_STOP){
157+ if (notePerChannel[i] = = NOTE_STOP){
163158 cout << " OFF" ;
164159 }
165160 else {
@@ -195,6 +190,9 @@ void playSong(SteamControllerInfos* controller,const ParamsStruct params){
195190 cout << " Starting playback of " <<params.midiSong << endl;
196191 sleep (1 );
197192
193+ // This will contains the previous events accepted for each channel
194+ MidiFileEvent_t acceptedEventPerChannel[CHANNEL_COUNT] = {0 };
195+
198196 // Get current time point, will be used to know elapsed time
199197 std::chrono::steady_clock::time_point tOrigin = std::chrono::steady_clock::now ();
200198
@@ -203,49 +201,57 @@ void playSong(SteamControllerInfos* controller,const ParamsStruct params){
203201 while (currentEvent != NULL ){
204202 usleep (params.intervalUSec );
205203
204+ // This will contains the events to play
205+ MidiFileEvent_t eventsToPlay[CHANNEL_COUNT] = {NULL };
206+
206207 // We now need to play all events with tick < currentTime
207208 long currentTick = MidiFile_getTickFromTime (midifile,timeElapsedSince (tOrigin));
208209
209- // This will contain the events to send to the Steam Controller
210- MidiFileEvent_t eventsToPlay[CHANNEL_COUNT] = {NULL };
211-
212- // Iterate through all events until the current time
210+ // Iterate through all events until the current time, and selecte potential events to play
213211 for ( ; currentEvent != NULL && MidiFileEvent_getTick (currentEvent) < currentTick ; currentEvent = MidiFileEvent_getNextEventInFile (currentEvent)){
214212
215- // Only process Note events
216- if (!MidiFileEvent_isNoteEvent (currentEvent)) continue ;
213+ // Only process note start events or note end events matching previous event
214+ if (!MidiFileEvent_isNoteStartEvent (currentEvent) && ! MidiFileEvent_isNoteEndEvent (currentEvent)) continue ;
217215
218216 // Get channel event
219217 int eventChannel = MidiFileVoiceEvent_getChannel (currentEvent);
220218
221219 // If channel is other than 0 or 1, skip this event, we cannot play it with only 1 steam controller
222220 if (eventChannel < 0 || !(eventChannel < CHANNEL_COUNT)) continue ;
223221
224- // Check that this event is not masking another event
225- // ( this can happen when OFF and ON events share same timetick ,note and channel if OFF events arrives after ON event)
226- if ( isThisEventMaskingPreviousEvent (currentEvent, eventsToPlay [eventChannel])) continue ;
222+ // If event is note off and does not match previous played event, skip it
223+ if ( MidiFileEvent_isNoteEndEvent (currentEvent)){
224+ MidiFileEvent_t previousEvent = acceptedEventPerChannel [eventChannel];
227225
228- // If we arrive here, this event match all conditions
229- eventsToPlay[eventChannel]=currentEvent;
226+ // Skip if current event is not ending previous event,
227+ // or if they share the same tick ( end event after start evetn on same tick )
228+ if (MidiFileNoteStartEvent_getNote (previousEvent) != MidiFileNoteEndEvent_getNote (currentEvent)
229+ ||(MidiFileEvent_getTick (currentEvent) == MidiFileEvent_getTick (previousEvent)))
230+ continue ;
231+ }
232+
233+ // If we arrive here, this event is accepted
234+ eventsToPlay[eventChannel] = currentEvent;
235+ acceptedEventPerChannel[eventChannel]=currentEvent;
230236 }
231237
232238 // Now play the last events found
233239 for (int currentChannel = 0 ; currentChannel < CHANNEL_COUNT ; currentChannel++){
234240 MidiFileEvent_t selectedEvent = eventsToPlay[currentChannel];
235241
236242 // If no note event available on the channel, skip it
237- if (selectedEvent == NULL && !MidiFileEvent_isNoteEvent (selectedEvent)) continue ;
243+ if (!MidiFileEvent_isNoteEvent (selectedEvent)) continue ;
238244
239245 // Set note event
240- unsigned int eventNote = NOTE_STOP;
246+ int8_t eventNote = NOTE_STOP;
241247 if (MidiFileEvent_isNoteStartEvent (selectedEvent)){
242248 eventNote = MidiFileNoteStartEvent_getNote (selectedEvent);
243249 }
244250
251+ // Play notes
245252 SteamController_PlayNote (controller,currentChannel,eventNote);
246- displayCurrentNote (currentChannel, eventNote);
253+ displayPlayedNotes (currentChannel,eventNote);
247254 }
248-
249255 }
250256
251257 cout <<endl<< " Playback completed " << endl;
0 commit comments