{"action":"created","issue":{"url":"https://api.github.com/repos/danomatika/ofxMidi/issues/54","repository_url":"https://api.github.com/repos/danomatika/ofxMidi","labels_url":"https://api.github.com/repos/danomatika/ofxMidi/issues/54/labels{/name}","comments_url":"https://api.github.com/repos/danomatika/ofxMidi/issues/54/comments","events_url":"https://api.github.com/repos/danomatika/ofxMidi/issues/54/events","html_url":"https://github.com/danomatika/ofxMidi/issues/54","id":281951520,"node_id":"MDU6SXNzdWUyODE5NTE1MjA=","number":54,"title":"Crash when ofxMidi sends messages from multiple thread","user":{"login":"hiroMTB","id":193280,"node_id":"MDQ6VXNlcjE5MzI4MA==","avatar_url":"https://avatars1.githubusercontent.com/u/193280?v=4","gravatar_id":"","url":"https://api.github.com/users/hiroMTB","html_url":"https://github.com/hiroMTB","followers_url":"https://api.github.com/users/hiroMTB/followers","following_url":"https://api.github.com/users/hiroMTB/following{/other_user}","gists_url":"https://api.github.com/users/hiroMTB/gists{/gist_id}","starred_url":"https://api.github.com/users/hiroMTB/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hiroMTB/subscriptions","organizations_url":"https://api.github.com/users/hiroMTB/orgs","repos_url":"https://api.github.com/users/hiroMTB/repos","events_url":"https://api.github.com/users/hiroMTB/events{/privacy}","received_events_url":"https://api.github.com/users/hiroMTB/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":8,"created_at":"2017-12-14T01:21:20Z","updated_at":"2018-07-23T11:16:39Z","closed_at":"2018-07-21T21:01:18Z","author_association":"NONE","body":"ofxMidi always store MIDI message in local variable **message**.\r\n\r\nofxBaseMidiOut.h\r\n```\r\nvector<unsigned char> message;   //< message byte buffer\r\n```\r\n\r\nAnd then call MIDI API (e.g. RtAudio) to actually send data to device.\r\nThis design is ok for single thread app.\r\n\r\nBut If we send MIDI from **multiple thread**, it won't work as expected.\r\nWhen we send MIDI message simultaneously from different thread, each thread overwrites local vector and create strange data packet. This is typical \"data race\" situation of multi thread application. To solve this problem, many changes are expected.\r\n\r\nOn OS X, with RtAudio, API itself looks like multithread friendly, so we can bypass  **message** vector and call API directly like below.\r\n\r\nTemporary solution\r\nSending message directly without copy, via RtMidi native object(tested on OSX, works ok so far)\r\n```\r\n    ofxMidiOut mout;\r\n\r\n    void sendNoteOn(int midiCh, int noteNum, int velocity, int duration){\r\n        mout.sendNoteOn(midiCh, noteNum, velocity);  \r\n        std::thread noteOffThread( &MidiSender::sendNoteOff, this, midiCh, noteNum, duration);\r\n        noteOffThread.detach();\r\n    }\r\n\r\n    void sendNoteOff(int midiCh, int noteNum, int duration){\r\n        if(duration>0)\r\n            std::this_thread::sleep_for( chrono::microseconds(duration*1000) );\r\n\r\n        vector<unsigned char> noteOff;\r\n        noteOff.push_back(MIDI_NOTE_OFF+(midiCh-1));\r\n        noteOff.push_back(noteNum);\r\n        noteOff.push_back(0);\r\n        ofPtr<ofxBaseMidiOut> ofOut = mout.midiOut;\r\n        ofxRtMidiOut * rtOut = static_cast<ofxRtMidiOut*>(ofOut.get());\r\n        rtOut->midiOut.sendMessage(&noteOff);\r\n    }\r\n```"},"comment":{"url":"https://api.github.com/repos/danomatika/ofxMidi/issues/comments/407023220","html_url":"https://github.com/danomatika/ofxMidi/issues/54#issuecomment-407023220","issue_url":"https://api.github.com/repos/danomatika/ofxMidi/issues/54","id":407023220,"node_id":"MDEyOklzc3VlQ29tbWVudDQwNzAyMzIyMA==","user":{"login":"danomatika","id":480637,"node_id":"MDQ6VXNlcjQ4MDYzNw==","avatar_url":"https://avatars1.githubusercontent.com/u/480637?v=4","gravatar_id":"","url":"https://api.github.com/users/danomatika","html_url":"https://github.com/danomatika","followers_url":"https://api.github.com/users/danomatika/followers","following_url":"https://api.github.com/users/danomatika/following{/other_user}","gists_url":"https://api.github.com/users/danomatika/gists{/gist_id}","starred_url":"https://api.github.com/users/danomatika/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/danomatika/subscriptions","organizations_url":"https://api.github.com/users/danomatika/orgs","repos_url":"https://api.github.com/users/danomatika/repos","events_url":"https://api.github.com/users/danomatika/events{/privacy}","received_events_url":"https://api.github.com/users/danomatika/received_events","type":"User","site_admin":false},"created_at":"2018-07-23T11:16:39Z","updated_at":"2018-07-23T11:16:39Z","author_association":"OWNER","body":"What do you mean by 'S'?"}}
{"actor":{"display_login":"danomatika"}}