From dc3396c806d500802cb8a8dad15d3e46a9621954 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sat, 25 Feb 2023 13:53:21 +0800 Subject: [PATCH] Initial commit Add files with test program. --- .gitattributes | 2 ++ .gitignore | 8 +++++ CMakeLists.txt | 19 +++++++++++ cases.txt | 36 +++++++++++++++++++++ midi-utils.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++ midi-utils.h | 18 +++++++++++ test-note-names.c | 26 +++++++++++++++ 7 files changed, 190 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cases.txt create mode 100644 midi-utils.c create mode 100644 midi-utils.h create mode 100644 test-note-names.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6c0cc39 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# This makes the repo play nice with git on Windows +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a0f976 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +cmake-build-debug +*.o +CMakeFiles/ +CMakeCache.txt +Makefile +cmake_install.cmake +example +.idea/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..772f609 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.24) +project(midi_note_id_utils C) + +set(CMAKE_C_STANDARD 11) + +include_directories(.) + +add_executable(test-note-names + test-note-names.c + midi-utils.c + midi-utils.h) + + +add_custom_command( + TARGET test-note-names POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_HOME_DIRECTORY}/cases.txt" + $ +) diff --git a/cases.txt b/cases.txt new file mode 100644 index 0000000..1c57e15 --- /dev/null +++ b/cases.txt @@ -0,0 +1,36 @@ +C0 0 +C#0 1 +D0 2 +D#0 3 +E0 4 +F0 5 +F#0 6 +G0 7 +G#0 8 +A0 9 +A#0 10 +B0 11 +C1 12 +C2 24 +C3 36 +C4 48 +C5 60 +A5 69 +C6 72 +C7 84 +C8 96 +C9 108 +C10 120 +G10 127 +C11 132 +C12 144 +C13 156 +C14 168 +C15 180 +C16 192 +C17 204 +C18 216 +C19 228 +C20 240 +C21 252 +D#21 255 diff --git a/midi-utils.c b/midi-utils.c new file mode 100644 index 0000000..626a00e --- /dev/null +++ b/midi-utils.c @@ -0,0 +1,81 @@ +#include "midi-utils.h" + +char* MIDI_GetNoteName(unsigned char midi_note) { + static const char* pitch_names[] = { + "C", + "C#", + "D", + "D#", + "E", + "F", + "F#", + "G", + "G#", + "A", + "A#", + "B" + }; + + const unsigned char pitch_class = midi_note % 12; + const unsigned char octave = midi_note / 12; + static char note_name[8]; + sprintf(note_name, "%s%u", pitch_names[pitch_class], octave); + return note_name; +} + +unsigned char MIDI_GetNoteFromName(const char* name) { + char name_copy[8]; + strcpy(name_copy, name); + _strlwr(name_copy); + + unsigned char octave = 0; + unsigned char has_accidental = name_copy[1] == '#' || name_copy[1] == 'b'; + unsigned char octave_start = has_accidental ? 2 : 1; + unsigned char pitch_class; + char octave_offset = 0; + + for (unsigned char i = octave_start; '0' <= name_copy[i] && name_copy[i] <= '9'; i += 1) { + octave *= 10; + octave += name_copy[i] - '0'; + } + + if (strstr(name_copy, "c#") || strstr(name_copy, "db")) { + pitch_class = 1; + } else if (strstr(name_copy, "d#") || strstr(name_copy, "eb")) { + pitch_class = 3; + } else if (strstr(name_copy, "fb")) { + pitch_class = 4; + } else if (strstr(name_copy, "e#")) { + pitch_class = 5; + } else if (strstr(name_copy, "f#") || strstr(name_copy, "gb")) { + pitch_class = 6; + } else if (strstr(name_copy, "g#") || strstr(name_copy, "ab")) { + pitch_class = 8; + } else if (strstr(name_copy, "a#") || strstr(name_copy, "bb")) { + pitch_class = 10; + } else if (strstr(name_copy, "cb")) { + pitch_class = 11; + octave_offset = -1; + } else if (strstr(name_copy, "b#")) { + pitch_class = 0; + octave_offset = 1; + } else if (strstr(name_copy, "c")) { + pitch_class = 0; + } else if (strstr(name_copy, "d")) { + pitch_class = 2; + } else if (strstr(name_copy, "e")) { + pitch_class = 4; + } else if (strstr(name_copy, "f")) { + pitch_class = 5; + } else if (strstr(name_copy, "g")) { + pitch_class = 7; + } else if (strstr(name_copy, "a")) { + pitch_class = 9; + } else if (strstr(name_copy, "b")) { + pitch_class = 11; + } else { + return 255u; + } + + return ((octave * 12) + octave_offset) + pitch_class; +} diff --git a/midi-utils.h b/midi-utils.h new file mode 100644 index 0000000..772d7ee --- /dev/null +++ b/midi-utils.h @@ -0,0 +1,18 @@ +#ifndef MIDI_UTILS_H +#define MIDI_UTILS_H + +#include +#include + +#define MIDI_MESSAGE_NOTEON 0x90u +#define MIDI_MESSAGE_NOTEOFF 0x80u + +#define MIDI_CC_SUSTAIN 0x40u +#define MIDI_CC_SOSTENUTO 0x42u +#define MIDI_CC_UNACORDA 0x43u + +char* MIDI_GetNoteName(unsigned char); + +unsigned char MIDI_GetNoteFromName(const char*); + +#endif diff --git a/test-note-names.c b/test-note-names.c new file mode 100644 index 0000000..aa3fdcc --- /dev/null +++ b/test-note-names.c @@ -0,0 +1,26 @@ +#include +#include +#include "midi-utils.h" + +int main(void) { + FILE* f = fopen("cases.txt", "r"); + if (!f) { + return -1; + } + char read_note_name[255] = ""; + unsigned int read_note_value; + while (!feof(f)) { + fscanf(f, "%s %d\n", read_note_name, &read_note_value); + unsigned int actual_note_value = MIDI_GetNoteFromName(read_note_name); + printf("MIDI_GetNoteFromName(\"%s\")...", read_note_name); + assert(read_note_value == actual_note_value); + printf("OK!\n"); + + printf("MIDI_GetNoteName(%d)...", read_note_value); + assert(!strcmp(MIDI_GetNoteName(read_note_value), read_note_name)); + printf("OK!\n"); + } + + fclose(f); + return 0; +}