2D Run-and-gun shooter inspired by One Man's Doomsday, Counter-Strike, and Metal Slug.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

192 lines
5.9 KiB

  1. #include "IZ_midi.h"
  2. static INI_ConfigItem midi_input_config_items[(IZ_PLAYERS * (IZ_CONTROLS + 2)) + 1];
  3. bool IZ_MIDIInputIsValidChannel(u8 value) {
  4. return (0 <= value && value <= 15);
  5. }
  6. void IZ_MIDIInputSerializeControl(i32 value, char* control[128]) {
  7. const char* serialized = MIDI_GetNoteName(value);
  8. IZ_memcpy(control, 128, serialized, 128);
  9. }
  10. i32 IZ_MIDIInputDeserializeControl(const char* control) {
  11. return MIDI_GetNoteFromName(control);
  12. }
  13. void IZ_MIDIInputHandleNoteOnOffEvents(IZ_MIDIInputState* state, IZ_Action* action, PmEvent e) {
  14. u32 message = e.message;
  15. u8 status = message & 0xF0u;
  16. u8 channel = message & 0x0Fu;
  17. u8 data1 = (message >> 8) & 0xFFu;
  18. // u8 data2 = (message >> 16) & 0xFFu;
  19. u8 control_index;
  20. for (control_index = 0; control_index < IZ_CONTROLS; control_index += 1) {
  21. if (
  22. data1 == state->config.control_mapping[control_index]
  23. && (
  24. (state->config.channel < 16 && channel == state->config.channel)
  25. || state->config.channel >= 16
  26. )
  27. ) {
  28. const u16 bitflag = (0x1 << control_index);
  29. if (status == MIDI_MESSAGE_NOTEON) {
  30. *action |= bitflag;
  31. return;
  32. }
  33. if (status == MIDI_MESSAGE_NOTEOFF) {
  34. *action &= ~bitflag;
  35. return;
  36. }
  37. }
  38. }
  39. }
  40. void IZ_MIDIInputHandleEvents(IZ_MIDIInputState(* state)[IZ_PLAYERS], IZ_Action(* action)[IZ_PLAYERS], PmEvent e) {
  41. u8 player_index;
  42. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  43. IZ_MIDIInputHandleNoteOnOffEvents(&(*state)[player_index], &(*action)[player_index], e);
  44. }
  45. }
  46. void IZ_MIDIInputBindStateToConfig(IZ_MIDIInputState(* state)[IZ_PLAYERS], INI_ConfigItem config_items[]) {
  47. u8 player_index;
  48. u8 control_index;
  49. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  50. u8 base_index = (player_index * (IZ_CONTROLS + 2));
  51. config_items[base_index].dest = &((*state)[player_index].config.device_id);
  52. config_items[base_index + 1].dest = &((*state)[player_index].config.channel);
  53. for (control_index = 0; control_index < IZ_CONTROLS; control_index += 1) {
  54. config_items[base_index + 2 + control_index].dest = &((*state)[player_index].config.control_mapping[control_index]);
  55. }
  56. }
  57. }
  58. IZ_ProcedureResult IZ_MIDIInputSaveConfig(IZ_MIDIInputState(* state)[IZ_PLAYERS], const char* config_path) {
  59. IZ_MIDIInputBindStateToConfig(state, midi_input_config_items);
  60. return INI_ConfigSave(midi_input_config_items, config_path);
  61. }
  62. void IZ_MIDIInputInitializeConfigItems(INI_ConfigItem config_items[]) {
  63. u8 player_index;
  64. u8 control_index;
  65. char* main_section_name;
  66. char* control_mapping_section_name;
  67. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  68. main_section_name = IZ_calloc(64, sizeof(char));
  69. sprintf(main_section_name, "MIDIInput.%d", player_index);
  70. u16 base_index = (player_index * (IZ_CONTROLS + 2));
  71. config_items[base_index] = (INI_ConfigItem) {
  72. INI_CONFIG_TYPE_I32,
  73. main_section_name,
  74. "DeviceID",
  75. NULL,
  76. &IZ_MIDI_INPUT_DEFAULT_STATE[player_index].config.device_id,
  77. NULL,
  78. INI_CONFIG_TRANSFORMER_NONE,
  79. NULL,
  80. };
  81. config_items[base_index + 1] = (INI_ConfigItem) {
  82. INI_CONFIG_TYPE_U8,
  83. main_section_name,
  84. "Channel",
  85. NULL,
  86. &IZ_MIDI_INPUT_DEFAULT_STATE[player_index].config.channel,
  87. IZ_MIDIInputIsValidChannel,
  88. INI_CONFIG_TRANSFORMER_NONE,
  89. NULL,
  90. };
  91. control_mapping_section_name = IZ_calloc(64, sizeof(char));
  92. sprintf(control_mapping_section_name, "MIDIInput.%d.ControlMapping", player_index);
  93. for (control_index = 0; control_index < IZ_CONTROLS; control_index += 1) {
  94. config_items[base_index + 2 + control_index] = (INI_ConfigItem) {
  95. INI_CONFIG_TYPE_U8,
  96. control_mapping_section_name,
  97. IZ_ACTION_NAMES[control_index],
  98. NULL,
  99. &IZ_MIDI_INPUT_DEFAULT_STATE[player_index].config.control_mapping[control_index],
  100. NULL,
  101. {
  102. .serialize = IZ_MIDIInputSerializeControl,
  103. .deserialize = IZ_MIDIInputDeserializeControl,
  104. },
  105. NULL,
  106. };
  107. }
  108. }
  109. config_items[IZ_PLAYERS * (IZ_CONTROLS + 2)] = INI_CONFIG_ITEM_NULL;
  110. }
  111. IZ_ProcedureResult IZ_MIDIInputInitializeConfig(IZ_MIDIInputState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
  112. IZ_MIDIInputInitializeConfigItems(midi_input_config_items);
  113. IZ_MIDIInputBindStateToConfig(state, midi_input_config_items);
  114. if (INI_ConfigInitialize(midi_input_config_items, config_path, argc, argv) < 0) {
  115. return -1;
  116. }
  117. return 0;
  118. }
  119. IZ_ProcedureResult IZ_MIDIInputInitialize(IZ_MIDIInputState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
  120. if (Pm_Initialize()) {
  121. return -1;
  122. }
  123. IZ_memcpy(state, sizeof(IZ_MIDIInputState) * IZ_PLAYERS, &IZ_MIDI_INPUT_DEFAULT_STATE, sizeof(IZ_MIDIInputState) * IZ_PLAYERS);
  124. if (IZ_MIDIInputInitializeConfig(state, config_path, argc, argv) < 0) {
  125. return -2;
  126. }
  127. u8 player_index;
  128. u8 midi_devices_count = Pm_CountDevices();
  129. u8 input_midi_devices_count = 0;
  130. u8 device_index;
  131. for (device_index = 0; device_index < midi_devices_count; device_index += 1) {
  132. if (!Pm_GetDeviceInfo(device_index)->input) {
  133. continue;
  134. }
  135. // midi device can output messages for the app to receive
  136. input_midi_devices_count += 1;
  137. }
  138. for (player_index = 0; player_index < input_midi_devices_count; player_index += 1) {
  139. if (player_index >= IZ_PLAYERS) {
  140. break;
  141. }
  142. (*state)[player_index].device_info = Pm_GetDeviceInfo((*state)[player_index].config.device_id);
  143. (*state)[player_index].stream = NULL;
  144. Pm_OpenInput(
  145. &(*state)[player_index].stream,
  146. (*state)[player_index].config.device_id,
  147. NULL,
  148. MIDI_EVENT_BUFFER_SIZE,
  149. NULL,
  150. NULL
  151. );
  152. }
  153. INI_ConfigSaveResult post_config_save_result = IZ_MIDIInputSaveConfig(state, config_path);
  154. if (post_config_save_result < 0) {
  155. return -3;
  156. }
  157. return 0;
  158. }
  159. void IZ_MIDIInputTeardown(IZ_MIDIInputState(* state)[IZ_PLAYERS]) {
  160. u8 player_index;
  161. for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
  162. if (!(*state)[player_index].stream) {
  163. continue;
  164. }
  165. Pm_Close((*state)[player_index].stream);
  166. }
  167. }