├── .gitattributes ├── Resource ├── numberednotation.bmp ├── Pitch.txt └── Patch.txt ├── VS2017 ├── portmidi │ ├── portmidi.vcxproj.user │ ├── portmidi.vcxproj.filters │ └── portmidi.vcxproj ├── portsmf │ ├── portsmf.vcxproj.user │ ├── portsmf.vcxproj.filters │ └── portsmf.vcxproj ├── MIDIPlayer │ ├── MIDIPlayer.vcxproj.user │ ├── MIDIPlayer.vcxproj.filters │ └── MIDIPlayer.vcxproj └── MIDIPlayer.sln ├── .gitmodules ├── README.md ├── Source ├── notation.cpp ├── parse.h ├── midiplayer.cpp ├── main.cpp ├── notation.h ├── test.cpp ├── parse.cpp └── midiplayer.h ├── .gitignore ├── CMakeLists.txt └── LICENSE /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | -------------------------------------------------------------------------------- /Resource/numberednotation.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RemiliaMIDIMaker/MIDIPlayer/HEAD/Resource/numberednotation.bmp -------------------------------------------------------------------------------- /VS2017/portmidi/portmidi.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /VS2017/portsmf/portsmf.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /VS2017/MIDIPlayer/MIDIPlayer.vcxproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ThirdLibrary/portmidi"] 2 | path = ThirdLibrary/portmidi 3 | url = https://github.com/RemiliaMIDIMaker/portmidi 4 | [submodule "ThirdLibrary/portsmf"] 5 | path = ThirdLibrary/portsmf 6 | url = https://github.com/RemiliaMIDIMaker/portsmf 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MIDI-Player 2 | The MIDI Player with Text and Binary File 3 | 4 | ## Build 5 | 6 | ### Windows 7 | 8 | #### Visual Studio 2017 9 | 10 | Open ./VS2017/MIDIPlayer.sln 11 | 12 | #### MinGW or Other 13 | 14 | Require CMake 15 | 16 | ``` 17 | mkdir build 18 | cd build 19 | cmake .. 20 | make 21 | ``` 22 | 23 | ### Linux 24 | 25 | Require CMake, Alsa 26 | 27 | ``` 28 | mkdir build 29 | cd build 30 | cmake .. 31 | make 32 | ``` 33 | 34 | 35 | ## License 36 | 37 | MIT 38 | -------------------------------------------------------------------------------- /Source/notation.cpp: -------------------------------------------------------------------------------- 1 | #include "notation.h" 2 | 3 | namespace MIDIPlayer 4 | { 5 | Pitch offset(const Pitch &pitch, const Notation ¬ation, bool &success) { 6 | assert(notation.base.data != 0); 7 | static const int8_t table[] = { 0, 1, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 12 }; 8 | int offset = table[notation.base.data - 1] + 0xc * notation.octave.data; 9 | int ndata = pitch.data + offset; 10 | success = (0 <= ndata && ndata <= 0x7f); 11 | return (success) ? Pitch(ndata) : Pitch(0); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Source/parse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "midiplayer.h" 3 | #include "notation.h" 4 | 5 | // Example : #C4 C#4 6 | MIDIPlayer::Pitch parsePitch(const char *word, const char *&end); 7 | 8 | // Example : 1 2# +1 --1 9 | MIDIPlayer::Notation parseNumberedNotation(const char *word, const char *&end); 10 | 11 | // Example : -- // //. 12 | MIDIPlayer::NoteValue parseNoteValueBase(const char *word, const char *&end); 13 | 14 | // Example : --&-- //.--&/.- 15 | MIDIPlayer::NoteValue parseNoteValue(const char *word, const char *&end); 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Other 35 | 36 | Debug 37 | Release 38 | x64/Debug 39 | x64/Release 40 | MIDIPlayer/Debug 41 | MIDIPlayer/Release 42 | MIDIPlayer/x64/Debug 43 | MIDIPlayer/x64/Release 44 | .vs 45 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | project(MIDIPlayer) 3 | 4 | include_directories(Source) 5 | 6 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -std=c++14") 7 | 8 | add_subdirectory(ThirdLibrary/portmidi) 9 | add_subdirectory(ThirdLibrary/portsmf) 10 | 11 | aux_source_directory(Source SOURCE_FILES) 12 | file(GLOB_RECURSE INCLUDE_FILES "*.h") 13 | 14 | include(ThirdLibrary/portmidi/lib_needed.cmake) 15 | message("Require Library of portmidi : ${PM_NEEDED_LIBS}") 16 | 17 | add_executable(midiplayer ${SOURCE_FILES}) 18 | target_link_libraries(midiplayer portmidi) 19 | target_link_libraries(midiplayer portsmf) 20 | target_link_libraries(midiplayer ${PM_NEEDED_LIBS}) 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Chill Magic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Resource/Pitch.txt: -------------------------------------------------------------------------------- 1 | Hex Octave Note 2 | 00 -1 C 3 | 01 -1 #C 4 | 02 -1 D 5 | 03 -1 #D 6 | 04 -1 E 7 | 05 -1 F 8 | 06 -1 #F 9 | 07 -1 G 10 | 08 -1 #G 11 | 09 -1 A 12 | 0A -1 #A 13 | 0B -1 B 14 | 0C 0 C 15 | 0D 0 #C 16 | 0E 0 D 17 | 0F 0 #D 18 | 10 0 E 19 | 11 0 F 20 | 12 0 #F 21 | 13 0 G 22 | 14 0 #G 23 | 15 0 A 24 | 16 0 #A 25 | 17 0 B 26 | 18 1 C 27 | 19 1 #C 28 | 1A 1 D 29 | 1B 1 #D 30 | 1C 1 E 31 | 1D 1 F 32 | 1E 1 #F 33 | 1F 1 G 34 | 20 1 #G 35 | 21 1 A 36 | 22 1 #A 37 | 23 1 B 38 | 24 2 C 39 | 25 2 #C 40 | 26 2 D 41 | 27 2 #D 42 | 28 2 E 43 | 29 2 F 44 | 2A 2 #F 45 | 2B 2 G 46 | 2C 2 #G 47 | 2D 2 A 48 | 2E 2 #A 49 | 2F 2 B 50 | 30 3 C 51 | 31 3 #C 52 | 32 3 D 53 | 33 3 #D 54 | 34 3 E 55 | 35 3 F 56 | 36 3 #F 57 | 37 3 G 58 | 38 3 #G 59 | 39 3 A 60 | 3A 3 #A 61 | 3B 3 B 62 | 3C 4 C 63 | 3D 4 #C 64 | 3E 4 D 65 | 3F 4 #D 66 | 40 4 E 67 | 41 4 F 68 | 42 4 #F 69 | 43 4 G 70 | 44 4 #G 71 | 45 4 A 72 | 46 4 #A 73 | 47 4 B 74 | 48 5 C 75 | 49 5 #C 76 | 4A 5 D 77 | 4B 5 #D 78 | 4C 5 E 79 | 4D 5 F 80 | 4E 5 #F 81 | 4F 5 G 82 | 50 5 #G 83 | 51 5 A 84 | 52 5 #A 85 | 53 5 B 86 | 54 6 C 87 | 55 6 #C 88 | 56 6 D 89 | 57 6 #D 90 | 58 6 E 91 | 59 6 F 92 | 5A 6 #F 93 | 5B 6 G 94 | 5C 6 #G 95 | 5D 6 A 96 | 5E 6 #A 97 | 5F 6 B 98 | 60 7 C 99 | 61 7 #C 100 | 62 7 D 101 | 63 7 #D 102 | 64 7 E 103 | 65 7 F 104 | 66 7 #F 105 | 67 7 G 106 | 68 7 #G 107 | 69 7 A 108 | 6A 7 #A 109 | 6B 7 B 110 | 6C 8 C 111 | 6D 8 #C 112 | 6E 8 D 113 | 6F 8 #D 114 | 70 8 E 115 | 71 8 F 116 | 72 8 #F 117 | 73 8 G 118 | 74 8 #G 119 | 75 8 A 120 | 76 8 #A 121 | 77 8 B 122 | 78 9 C 123 | 79 9 #C 124 | 7A 9 D 125 | 7B 9 #D 126 | 7C 9 E 127 | 7D 9 F 128 | 7E 9 #F 129 | 7F 9 G 130 | -------------------------------------------------------------------------------- /Source/midiplayer.cpp: -------------------------------------------------------------------------------- 1 | #include "midiplayer.h" 2 | #include 3 | #include "../ThirdLibrary/portmidi/include/portmidi.h" 4 | #include "../ThirdLibrary/portmidi/include/porttime.h" 5 | 6 | namespace MIDIPlayer 7 | { 8 | // Player::MIDIDevice 9 | 10 | static PortMidiStream*& getMIDIDevice(void* &data) { 11 | return reinterpret_cast(data); 12 | } 13 | static PortMidiStream*& getMIDIDevice(Player::MIDIDevice &midi_device) { 14 | return getMIDIDevice(midi_device.get()); 15 | } 16 | 17 | void Player::MIDIDevice::open(void* &data) { 18 | if (Pm_OpenOutput(&getMIDIDevice(data), Pm_GetDefaultOutputDeviceID(), nullptr, 0, nullptr, nullptr, 0)) { 19 | printf("There is an error opening the default MIDI out device!\n"); 20 | } 21 | } 22 | void Player::MIDIDevice::close(void* data) { 23 | Pm_Close(getMIDIDevice(data)); 24 | } 25 | void*& Player::MIDIDevice::get() { 26 | return data; 27 | } 28 | 29 | // Player 30 | 31 | static size_t PmUsageCounter = 0; 32 | 33 | Player::Player() { 34 | Pm_Initialize(); 35 | PmUsageCounter++; 36 | } 37 | Player::Player(const Player &) { 38 | PmUsageCounter++; 39 | } 40 | 41 | Player::~Player() { 42 | PmUsageCounter--; 43 | if (PmUsageCounter == 0) { 44 | Pm_Terminate(); 45 | } 46 | } 47 | 48 | static void _Pm_WriteShort(PortMidiStream *stream, PmMessage message) { 49 | Pm_WriteShort(stream, 0, message); 50 | } 51 | 52 | void Player::PlayPitch(MIDIDevice midi_device, Pitch pitch, Volume volume, Track track) { 53 | _Pm_WriteShort(getMIDIDevice(midi_device), ((volume.data * 0x10000) | (pitch.data * 0x100) | (track.data + 0x90))); 54 | } 55 | void Player::ClosePitch(MIDIDevice midi_device, Pitch pitch, Track track) { 56 | _Pm_WriteShort(getMIDIDevice(midi_device), ((pitch.data * 0x100) | (track.data + 0x80))); 57 | } 58 | void Player::ChangePatch(MIDIDevice midi_device, Patch patch, Track track) { 59 | _Pm_WriteShort(getMIDIDevice(midi_device), ((patch.data * 0x100) | (track.data + 0xc0))); 60 | } 61 | void Player::Sleep(DeTime detime) { 62 | Pt_Sleep(detime.data); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/main.cpp: -------------------------------------------------------------------------------- 1 | #include "midiplayer.h" 2 | #include "notation.h" 3 | #include "parse.h" 4 | #include 5 | #include 6 | 7 | #ifndef NDEBUG 8 | void Test(); 9 | #endif 10 | 11 | int main(int argc, const char *argv[]) 12 | { 13 | using namespace MIDIPlayer; 14 | 15 | #ifndef NDEBUG 16 | Test(); 17 | #endif 18 | 19 | Player player; 20 | 21 | bool play_end = false; 22 | std::thread t1([&]() { 23 | auto playerc = player.Create(Track(0), Patch(0)); 24 | 25 | Pitch base(Note("C")); 26 | 27 | Notation not1(NotationBase(1, false), NotationOctave(0)); 28 | Notation not2(NotationBase(2, false), NotationOctave(0)); 29 | Notation not3(NotationBase(3, false), NotationOctave(0)); 30 | Notation not4(NotationBase(4, false), NotationOctave(0)); 31 | Notation not5(NotationBase(5, false), NotationOctave(0)); 32 | 33 | playerc.PlayPitch(not1 + base, DeTime(500)); 34 | playerc.PlayPitch(not1 + base, DeTime(500)); 35 | playerc.PlayPitch(not3 + base, DeTime(500)); 36 | playerc.PlayPitch(not5 + base, DeTime(500)); 37 | playerc.PlayPitch(not5 + base, DeTime(1000)); 38 | 39 | playerc.PlayPitch(not5 + base, DeTime(500)); 40 | playerc.PlayPitch(not5 + base, DeTime(1000)); 41 | playerc.PlayPitch(not3 + base, DeTime(500)); 42 | playerc.PlayPitch(not3 + base, DeTime(1000)); 43 | 44 | playerc.PlayPitch(not1 + base, DeTime(500)); 45 | playerc.PlayPitch(not1 + base, DeTime(500)); 46 | playerc.PlayPitch(not3 + base, DeTime(500)); 47 | playerc.PlayPitch(not5 + base, DeTime(500)); 48 | playerc.PlayPitch(not5 + base, DeTime(1000)); 49 | 50 | playerc.PlayPitch(not5 + base, DeTime(500)); 51 | playerc.PlayPitch(not5 + base, DeTime(1000)); 52 | playerc.PlayPitch(not4 + base, DeTime(500)); 53 | playerc.PlayPitch(not4 + base, DeTime(1000)); 54 | 55 | play_end = true; 56 | }); 57 | 58 | std::thread t2([&]() { 59 | auto playerc = player.Create(Track(1), Patch(0)); 60 | playerc.Sleep(DeTime(500)); 61 | 62 | while (!play_end) { 63 | playerc.PlayPitch(Pitch(Note(NoteBase(5)), Octave(3)), DeTime(500)); 64 | } 65 | }); 66 | 67 | t1.join(); 68 | t2.join(); 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /VS2017/MIDIPlayer/MIDIPlayer.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 源文件 29 | 30 | 31 | 源文件 32 | 33 | 34 | 35 | 36 | 头文件 37 | 38 | 39 | 头文件 40 | 41 | 42 | 头文件 43 | 44 | 45 | 46 | 47 | 资源文件 48 | 49 | 50 | 资源文件 51 | 52 | 53 | 54 | 55 | 资源文件 56 | 57 | 58 | -------------------------------------------------------------------------------- /Source/notation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "midiplayer.h" 3 | #include 4 | 5 | namespace MIDIPlayer 6 | { 7 | struct NotationBase { // 0, 1 ~ 14; (1 ~ 7, true/false) 8 | explicit NotationBase() : data(0) {} 9 | explicit NotationBase(uint8_t data, bool rise) : data((data * 2 - 1) + (rise ? 1 : 0)) { assert(1 <= data && data <= 7); } 10 | uint8_t data; 11 | }; 12 | struct NotationOctave { // -11 ~ 10 13 | explicit NotationOctave(int8_t data = 0) : data(data) {} 14 | int8_t data; 15 | }; 16 | struct Notation { 17 | explicit Notation() {} 18 | explicit Notation(NotationBase base, NotationOctave octave) : base(base), octave(octave) {} 19 | NotationBase base; 20 | NotationOctave octave; 21 | }; 22 | 23 | struct NoteValue { 24 | // 1--- : 1 note : 256 25 | // 1- : 1/2 note : 128 26 | // 1 : 1/4 note : 64 27 | // 1/ : 1/8 note : 32 28 | // 1// : 1/16 note : 16 29 | // 1/// : 1/32 note : 8 30 | // 1//// : 1/64 note : 4 31 | // 1///// : 1/128 note : 2 32 | // 1////// : 1/256 note : 1 33 | 34 | // 1. : 1/4 + 1/8 : 64 + 32 = 96 35 | // 1/. : 1/8 + 1/16 : 32 + 16 = 48 36 | // 1---.. : 1 + 1/2 + 1/4 : 256 + 128 + 64 = 448 = 7 * 64 : 1------- 37 | 38 | using Type = uint16_t; 39 | constexpr static Type WholeNote = 256; 40 | 41 | explicit NoteValue(Type data) : data(data) { /*assert(data != 0);*/ } 42 | 43 | NoteValue& operator+=(const NoteValue &nv) { 44 | *this = *this + nv; 45 | return *this; 46 | } 47 | NoteValue operator+(const NoteValue &nv) const { 48 | assert(data + nv.data <= std::numeric_limits::max()); 49 | return NoteValue(data + nv.data); 50 | } 51 | Type data; 52 | }; 53 | 54 | // if 1 = C4 then 1# = #C4, 2 = D4, 2# = #D4 ... 55 | // Notice : 3# == 4, 7# == +1, whatever 1 = what. 56 | Pitch offset(const Pitch &pitch, const Notation ¬ation, bool &success); 57 | inline Pitch operator+(const Pitch &pitch, const Notation ¬ation) { 58 | bool success; 59 | auto r = offset(pitch, notation, success); 60 | assert(success); 61 | return r; 62 | } 63 | inline Pitch operator+(const Notation ¬ation, const Pitch &pitch) { 64 | return pitch + notation; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /VS2017/portmidi/portmidi.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 源文件 29 | 30 | 31 | 源文件 32 | 33 | 34 | 源文件 35 | 36 | 37 | 38 | 39 | 头文件 40 | 41 | 42 | 头文件 43 | 44 | 45 | 头文件 46 | 47 | 48 | 头文件 49 | 50 | 51 | 源文件 52 | 53 | 54 | -------------------------------------------------------------------------------- /VS2017/portsmf/portsmf.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 源文件 20 | 21 | 22 | 源文件 23 | 24 | 25 | 源文件 26 | 27 | 28 | 源文件 29 | 30 | 31 | 源文件 32 | 33 | 34 | 源文件 35 | 36 | 37 | 源文件 38 | 39 | 40 | 源文件 41 | 42 | 43 | 44 | 45 | 头文件 46 | 47 | 48 | 头文件 49 | 50 | 51 | 头文件 52 | 53 | 54 | 头文件 55 | 56 | 57 | 头文件 58 | 59 | 60 | 头文件 61 | 62 | 63 | -------------------------------------------------------------------------------- /Source/test.cpp: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | 3 | static void Test1() { 4 | using namespace MIDIPlayer; 5 | 6 | char s; 7 | uint8_t v; 8 | char word[5] = ""; 9 | const char *end; 10 | for (int o = -1; o <= 9; o++) { 11 | for (int i = 1; i <= 7; i++) { 12 | if (i == 6 || i == 7) 13 | s = 'A' + i - 6; 14 | else 15 | s = 'C' + i - 1; 16 | 17 | if (!(s == 'C' && o == -1)) { 18 | sprintf(word, "b%c%d", s, o); 19 | v = parsePitch(word, end).data; 20 | printf("%s 0x%02x\n", word, v); 21 | assert(v == Pitch(Note(NoteBase(s), KeySignature('b')), Octave(o)).data); 22 | assert(end == word + ((o == -1) ? 4 : 3)); 23 | } 24 | sprintf(word, "%c%d", s, o); 25 | v = parsePitch(word, end).data; 26 | printf(" %s 0x%02x\n", word, v); 27 | assert(v == Pitch(Note(NoteBase(s), KeySignature('\0')), Octave(o)).data); 28 | assert(end == word + ((o == -1) ? 3 : 2)); 29 | if (s == 'G' && o == 9) 30 | break; 31 | sprintf(word, "#%c%d", s, o); 32 | v = parsePitch(word, end).data; 33 | printf("%s 0x%02x\n", word, v); 34 | assert(v == Pitch(Note(NoteBase(s), KeySignature('#')), Octave(o)).data); 35 | assert(end == word + ((o == -1) ? 4 : 3)); 36 | } 37 | } 38 | } 39 | 40 | static void Test2_Base(MIDIPlayer::Pitch base) { 41 | using namespace MIDIPlayer; 42 | char word[0x10] = ""; 43 | 44 | for (int o = -11; o <= 10; o++) { 45 | for (int i = 1; i <= 7; i++) { 46 | bool success = true; 47 | const char *end; 48 | 49 | int x = 0; 50 | int count = o > 0 ? o : -o; 51 | while (count--) 52 | word[x++] = (o > 0 ? '+' : '-'); 53 | word[x++] = i + '0'; 54 | word[x] = '\0'; 55 | 56 | { 57 | Notation notation(NotationBase(i, false), NotationOctave(o)); 58 | Notation notation_p = parseNumberedNotation(word, end); 59 | assert(notation.base.data == notation_p.base.data); 60 | assert(notation.octave.data == notation_p.octave.data); 61 | assert(end == word + o + 1); 62 | printf("%s\n", word); 63 | } 64 | 65 | word[x++] = '#'; 66 | word[x] = '\0'; 67 | 68 | { 69 | Notation notation(NotationBase(i, true), NotationOctave(o)); 70 | Notation notation_p = parseNumberedNotation(word, end); 71 | assert(notation.base.data == notation_p.base.data); 72 | assert(notation.octave.data == notation_p.octave.data); 73 | assert(end == word + o + 2); 74 | printf("%s\n", word); 75 | } 76 | } 77 | } 78 | } 79 | 80 | static void Test2() 81 | { 82 | using namespace MIDIPlayer; 83 | Pitch base(Note("C"), Octave(-1)); 84 | 85 | Test2_Base(base); 86 | } 87 | 88 | static void Test3() 89 | { 90 | char buffer[0xff] = ""; 91 | const char *end; 92 | 93 | while (true) { 94 | printf(">"); 95 | scanf("%s", buffer); 96 | auto v = parseNoteValue(buffer, end); 97 | printf("%d %lld\n", v.data, end - buffer); 98 | } 99 | } 100 | 101 | void Test() 102 | { 103 | //Test1(); 104 | //Test2(); 105 | //Test3(); 106 | } 107 | -------------------------------------------------------------------------------- /VS2017/MIDIPlayer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MIDIPlayer", "MIDIPlayer\MIDIPlayer.vcxproj", "{96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {587F1535-A0E9-4560-B896-A4F6D2F83300} = {587F1535-A0E9-4560-B896-A4F6D2F83300} 9 | {94247963-30D9-4118-B1C5-4B13E57F0158} = {94247963-30D9-4118-B1C5-4B13E57F0158} 10 | EndProjectSection 11 | EndProject 12 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portmidi", "portmidi\portmidi.vcxproj", "{94247963-30D9-4118-B1C5-4B13E57F0158}" 13 | EndProject 14 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "portsmf", "portsmf\portsmf.vcxproj", "{587F1535-A0E9-4560-B896-A4F6D2F83300}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|x64 = Debug|x64 19 | Debug|x86 = Debug|x86 20 | Release|x64 = Release|x64 21 | Release|x86 = Release|x86 22 | EndGlobalSection 23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 24 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Debug|x64.ActiveCfg = Debug|x64 25 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Debug|x64.Build.0 = Debug|x64 26 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Debug|x86.ActiveCfg = Debug|Win32 27 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Debug|x86.Build.0 = Debug|Win32 28 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Release|x64.ActiveCfg = Release|x64 29 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Release|x64.Build.0 = Release|x64 30 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Release|x86.ActiveCfg = Release|Win32 31 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE}.Release|x86.Build.0 = Release|Win32 32 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Debug|x64.ActiveCfg = Debug|x64 33 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Debug|x64.Build.0 = Debug|x64 34 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Debug|x86.ActiveCfg = Debug|Win32 35 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Debug|x86.Build.0 = Debug|Win32 36 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Release|x64.ActiveCfg = Release|x64 37 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Release|x64.Build.0 = Release|x64 38 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Release|x86.ActiveCfg = Release|Win32 39 | {94247963-30D9-4118-B1C5-4B13E57F0158}.Release|x86.Build.0 = Release|Win32 40 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Debug|x64.ActiveCfg = Debug|x64 41 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Debug|x64.Build.0 = Debug|x64 42 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Debug|x86.ActiveCfg = Debug|Win32 43 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Debug|x86.Build.0 = Debug|Win32 44 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Release|x64.ActiveCfg = Release|x64 45 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Release|x64.Build.0 = Release|x64 46 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Release|x86.ActiveCfg = Release|Win32 47 | {587F1535-A0E9-4560-B896-A4F6D2F83300}.Release|x86.Build.0 = Release|Win32 48 | EndGlobalSection 49 | GlobalSection(SolutionProperties) = preSolution 50 | HideSolutionNode = FALSE 51 | EndGlobalSection 52 | GlobalSection(ExtensibilityGlobals) = postSolution 53 | SolutionGuid = {FC0DC6E7-890E-4C8D-B2D5-FE44A7DE047B} 54 | EndGlobalSection 55 | EndGlobal 56 | -------------------------------------------------------------------------------- /Source/parse.cpp: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | 3 | MIDIPlayer::Pitch parsePitch(const char *word, const char *&end) { 4 | int num, i, j; 5 | char note[3]; 6 | num = i = j = 0; 7 | //judeg the first character 8 | if (word[i] != '#' && word[i] != 'b' && !(word[i] <= 'G' && word[i] >= 'A')) { 9 | printf("Illegal operation.The first character is not the correct character.\n"); 10 | end = word; 11 | return (MIDIPlayer::Pitch(0)); 12 | } 13 | note[j] = word[i++]; 14 | //save the next character when first one is # or b 15 | if (note[j] == '#' || note[j] == 'b') { 16 | if (word[i] <= 'G' && word[i] >= 'A') { 17 | note[++j] = word[i++]; 18 | } 19 | else { 20 | printf("Illegal operation.The character is not the charater between A and G.\n"); 21 | end = word; 22 | return (MIDIPlayer::Pitch(0)); 23 | } 24 | } 25 | //save the num 26 | if (word[i] == '-') { 27 | if (word[++i] == '1') 28 | num = -1; 29 | else { 30 | printf("Illegal operation.The number is under o but is not -1.\n"); 31 | end = word; 32 | return (MIDIPlayer::Pitch(0)); 33 | } 34 | } 35 | else if (word[i] <= '9' && word[i] >= '0') 36 | num = word[i] - '0'; 37 | else { 38 | printf("Illegal operation.There should be a number between 0 and 9.\n"); 39 | end = word; 40 | return (MIDIPlayer::Pitch(0)); 41 | } 42 | //judge the corret or not again 43 | if (note[0] == 'b' && note[1] == 'C' && num == -1) { 44 | printf("Illegal operation.There is no bC-1.\n"); 45 | end = word; 46 | return (MIDIPlayer::Pitch(0)); 47 | } 48 | else if (num == 9) { 49 | if ((note[0] == '#' && (note[1] == 'G' || note[1] == 'A')) || (note[0] == 'A' || note[0] == 'B')) { 50 | printf("Illegal operation.There is no #G A #A B when num == 9\n"); 51 | end = word; 52 | return (MIDIPlayer::Pitch(0)); 53 | } 54 | 55 | } 56 | end = &word[++i]; 57 | return MIDIPlayer::Pitch(MIDIPlayer::Note(word), MIDIPlayer::Octave(num)); 58 | } 59 | 60 | MIDIPlayer::Notation parseNumberedNotation(const char *word, const char *&end) { 61 | int base = 0; 62 | int octave = 0; 63 | int i = 0; 64 | bool rise; 65 | while (word[i] == '-' || word[i] == '+' || word[i] <= '7' && word[i] >= '1') { 66 | if (word[i] == '-') {//if the first character is - 67 | if (word[0] == '-')//if this character is - 68 | octave--; 69 | else {//if it is not ' either number of range 70 | printf("Illegal operation.The are wrong characters when first character is '-'.\n"); 71 | end = word; 72 | return MIDIPlayer::Notation(); 73 | } 74 | } 75 | else if (word[i] == '+') { 76 | if (word[0] == '+')//if this character is + 77 | octave++; 78 | else {//if it is not ' either number of range 79 | printf("Illegal operation.The are wrong characters when first character is '+'.\n"); 80 | end = word; 81 | return MIDIPlayer::Notation(); 82 | } 83 | } 84 | else { 85 | base = word[i] - '0'; 86 | if (word[i + 1] == '#') 87 | rise = true; 88 | else 89 | rise = false; 90 | break; 91 | } 92 | i++; 93 | } 94 | if (!base) { 95 | printf("Illegal operation.There are no base number in this string or there are wrong characters in it\n"); 96 | end = word; 97 | return MIDIPlayer::Notation(); 98 | } 99 | //printf("base:%d\t octave:%d\t rise:%d\n", base, octave, rise); 100 | end = &word[octave + 1 + rise]; 101 | return MIDIPlayer::Notation(MIDIPlayer::NotationBase(base, rise), MIDIPlayer::NotationOctave(octave)); 102 | } 103 | 104 | MIDIPlayer::NoteValue parseNoteValueBase(const char *word, const char *&end) { 105 | uint32_t sum = MIDIPlayer::NoteValue::WholeNote / 4; 106 | int i = 0; 107 | while (word[i] == '/' || word[i] == '.' || word[i] == '-') { 108 | while (word[i] == '/') { 109 | sum /= 2; 110 | i++; 111 | } 112 | int add = sum / 2; 113 | while (word[i] == '.') { 114 | sum += add; 115 | add /= 2; 116 | i++; 117 | } 118 | while (word[i] == '-') { 119 | sum += MIDIPlayer::NoteValue::WholeNote / 4; 120 | i++; 121 | } 122 | } 123 | end = &word[i]; 124 | if (sum == 0) { 125 | printf("Illegal Operation!The notevalue is too small.\n"); 126 | return MIDIPlayer::NoteValue(0); 127 | } 128 | else if (sum > std::numeric_limits::max()) { 129 | printf("Illegal Operation!The notevalue is too big.\n"); 130 | return MIDIPlayer::NoteValue(0); 131 | } 132 | else { 133 | return MIDIPlayer::NoteValue(static_cast(sum)); 134 | } 135 | } 136 | 137 | MIDIPlayer::NoteValue parseNoteValue(const char *word, const char *&end) { 138 | MIDIPlayer::NoteValue sum(0); 139 | sum = parseNoteValueBase(word, end); 140 | if (end == word) { 141 | return sum; 142 | } 143 | while (*end == '&') { 144 | const char *f = end + 1; 145 | auto r = parseNoteValueBase(end + 1, end); 146 | if (f == end) { 147 | end = f - 1; 148 | break; 149 | } 150 | sum += r; 151 | if (*f == '-') { 152 | assert(sum.data > MIDIPlayer::NoteValue::WholeNote / 4); 153 | sum.data -= MIDIPlayer::NoteValue::WholeNote / 4; 154 | } 155 | } 156 | 157 | return sum; 158 | } 159 | -------------------------------------------------------------------------------- /Resource/Patch.txt: -------------------------------------------------------------------------------- 1 | 标准GM乐器音色列表及大概讲解 2 | 钢琴 3 | 0 ACCOUSTIC GRAND PIANO 大钢琴(就是一般我们见到的那种) 4 | 音色比较浑厚,可以用于古典乐曲,进行曲,爵士乐等比较正规的(流行乐也可以的),在钢琴方面, 5 | 各种声卡做的都还不错的,可以作为和弦,也可以作为主音 6 | 1 BRIGHT ACCOUSTIC PIANO 明亮的钢琴 7 | 声音比较尖比较脆,不适合正规乐曲,可用于流行乐,电子乐等,多做主音 8 | 2 ELECTRIC GRAND PIANO 电钢琴 9 | 声音比BRIGHT ACCOUSTIC PIANO柔和一点,使用同上 10 | 3 HONKY-TONK PIANO 酒吧钢琴 11 | 声音很柔和,有点FLANGER的感觉,很重的电子倾向,用于流行乐,电子乐 12 | 4 RHODES PIANO 柔和的电钢琴 13 | 已经不像钢琴了,有嘟的声音,明显电子,可做和弦用,做和弦时可用于流行,电子甚至是爵士,有 14 | 很好的效果,但是如果做主音就听不大清了。 15 | 5 CHORUSED PIANO 加了合唱效果的电钢琴 16 | 声音比电钢琴闷一点,一听就是电子味道的 17 | 6 HARPSICHORD 羽管键琴(拨弦古钢琴) 18 | 可用于古典歌曲,教堂音乐,乡村音乐,声音有点扁,有点难听,但是做分解和弦的时候还不错的 19 | 7 CLAVICHORD 科拉维科特琴(击弦古钢琴) 20 | 音色也不是很好听,用法和HARPSICHORD相似 21 | 22 | 色彩打击乐器 23 | 8 CELESTA 钢片琴 24 | 叮咚的声音,各种场合都有可能用到,加长时值无效 25 | 9 GLOCKENSPIEL 钟琴 26 | 10 MUSIC BOX 八音盒 27 | 经常用于某些流行歌曲的开头,可用于电子乐,古典乐等,制造一种音很高的天籁之音的效果,可以提 28 | 高八度使用,加长时值无效 29 | 11 VIBRAPHONE 颤音琴 30 | 和MUSICBOX类似,也可提高八度用 31 | 12 MARIMBA 马林巴 32 | 可用作和弦,不适用庄严的歌 33 | 13 XYLOPHONE 木琴 34 | 多用于桑巴等爵士乐曲,声音脆,短,加长时值无效 35 | 14 TUBULAR BELLS 管钟 36 | 一般作为音效出现 37 | 15 DUCLIMER 大扬琴 38 | 这个不用说了,中国古典乐器 39 | 40 | 风琴 41 | 16 HAMMOND ORGAN 击杆风琴 42 | 音色较亮,适用于古典音乐,特别是教堂音乐,格兰蒂亚2可以见到 43 | 17 PERCUSSIVE ORGAN 打击式风琴 44 | 音色闷一点,比较忧伤,适用于古典音乐,特别是教堂音乐 45 | 18 ROCK ORGAN 摇滚风琴 46 | 顾名思义,多做主音,使用的时候经常用爬音阶的方式,就是用大拇指上滑或者下滑,记得用32分音符 47 | (尽量小一点),然后按照半音慢慢排列下来 48 | 19 CHURCH ORGAN 教堂风琴 49 | 还要说吗?音色比较直一点,不带强烈感情色彩 50 | 20 REED ORGAN 簧管风琴 51 | 与其他风琴不同的是它是吹出来的,用于古典乐 52 | 21 ACCORDIAN 手风琴 53 | 不用说了吧,有明显个性色彩的乐器 54 | 22 HARMONICA 口琴 55 | 23 TANGO ACCORDIAN 探戈手风琴 56 | 多用于探戈舞曲 57 | 58 | 吉他 59 | 24 ACOUSTIC GUITAR(NYLON)尼龙弦吉他(古典吉他) 60 | 用于古典乐,也会用于流行歌曲做伴奏或者有一段SOLO 61 | 25 ACOUSTIC GUITAR(STEEL) 钢弦吉他 62 | 多用于乐队演奏,做节奏吉他 63 | 26 ELECTRIC GUITAR(JAZZ) 爵士电吉他 64 | 爵士,流行都可用的 65 | 27 ELECTRIC GUITAR(CLEAN) 清音电吉他 66 | 多用做分解和弦 67 | 28 ELECTRIC GUITAR(MUTED) 闷音电吉他 68 | 产生闷音效果 69 | 29 OVERDRIVEN GUITAR 加驱动效果的电吉他 70 | 30 DISTORTION GUITAR 加失真效果的电吉他 71 | 这两种都带失真效果,主要用于ROCK 72 | 31 GUITAR HARMONICS 吉他和音(可以做泛音) 73 | 产生高8度的音,做泛音有比较好的效果,和失真吉他一起用 74 | 75 | 贝斯 76 | 32 ACOUSTIC BASS 大贝斯(声学贝斯) 77 | 用于古典,爵士 78 | 33 ELECTRIC BASS(FINGER) 电贝斯(指弹) 79 | 34 ELECTRIC BASS(PICK) 电贝斯(拨片) 80 | 这两种用于流行,摇滚等各种音乐(除了古典乐和独奏乐,BASS是不能少的),后者是用拨片弹的,脆 81 | 一点,前者用手弹的,实一点 82 | 35 FRETLESS BASS 无品贝斯 83 | 一种像小提琴的贝斯(不是说长的像啊,只是说它不标注品位),没有标注品位,所以音听起来不是很 84 | 准,但有一定的效果 85 | 36 SLAP BASS 1 勾打贝斯1 86 | 37 SLAP BASS 2 勾打贝斯2 87 | 这两种适用大拇指勾打贝斯的弦产生的,多用于FUNK 88 | 38 SYNTH BASS 1 电子合成贝斯1 89 | 39 SYNTH BASS 2 电子合成贝斯2 90 | 多用于电子乐 91 | 92 | 弦乐 93 | 40 VIOLIN 小提琴 94 | 41 VIOLA 中提琴 95 | 42 CELLO 大提琴 96 | 43 CONTRABASS 低音提琴 97 | 四种提琴音域依次往下降,CONTRABASS在古典乐中相当于BASS的作用 98 | VIOLIN,VIOLA可以独奏,全部都可以作为和弦(用16分音符)产生一种拉弦的效果 99 | 44 TREMOLO STRINGS 弦乐群颤音音色 100 | 有点像小提琴中的TR~~~~~(脆儿)所有弦乐器在半音范围内颤抖 101 | 45 PIZZICATO STRINGS 弦乐琴拨弦音色 102 | 多用于古典乐,NEWAGE,所有弦乐器一起拨弦的声音 103 | 46 ORCHESTRAL HARP 竖琴 104 | 用上下行的话可以加强乐曲气势,音色非常好听 105 | 47 TIMPANI 定音鼓 106 | 加强低音效果和气势,用的时候音不用太准的,最好不要使用它的高音 107 | 108 | 合奏/合唱 109 | 48 STRING ENSEMBLE 1 弦乐合奏音色1 110 | 声音较钢硬,有气势的 111 | 49 STRING ENSEMBLE 2 弦乐合奏音色2 112 | 声音较柔和,声音会延迟到达最大音量 113 | 都用于古典乐,流行乐做和弦或者做小提琴等乐器的铺垫音 114 | 50 SYNTH STRINGS 1 合成弦乐合奏音色1 115 | 51 SYNTH STRINGS 2 合成弦乐合奏音色2 116 | 用于电子乐流行乐做和弦 117 | 52 CHOIR AAHS 人声合唱“啊” 118 | 53 VOICE OOHS 人声“嘟” 119 | 54 SYNTH VOICE 合成人声 120 | 可以做乐曲主旋律或者和声的旋律 121 | 55 ORCHESTRA HIT 管弦乐敲击齐奏 122 | 很强的气势,每次最好只用一个音,加大它的力度就可以了 123 | 124 | 铜管 125 | 56 TRUMPET 小号 126 | 高音乐器,声音刚健挺拔 127 | 57 TROMBONE 长号 128 | 可以使用滑音,适合粗犷雄壮的曲调 129 | 58 TUBA 大号 130 | 低音乐器 131 | 59 MUTED TRUMPET 加弱音器的小号 132 | 60 FRENCH HORN 法国号(圆号) 133 | 音色柔和,常与木管乐器一起使用 134 | 61 BRASS SECTION 铜管组(铜管乐器合奏) 135 | 62 SYNTH BRASS 1 合成铜管音色 1 136 | 63 SYNTH BRASS 2 合成铜管音色 2 137 | 铜管组要配合使用,一般都会几个同时出现 138 | 139 | 簧管 140 | 64 SOPRANO SAX 高音萨克斯 141 | 65 ALTO SAX 次中音萨克斯 142 | 可用做主旋律,做主音的时候可以用滑音 143 | 66 TENOR SAX 中音萨克斯 144 | 67 BARITONE SAX 低音萨克斯 145 | SAX本来就是一种做主旋律的乐器,不能做和弦 146 | 68 OBOE 双簧管 147 | 69 ENGLISH HORN 英国管 148 | 70 BASSOON 巴松(大管) 149 | 71 CLARINET 单簧管(黑管) 150 | 151 | 笛 152 | 72 PICCOLO 短笛 153 | 尖锐的声音 154 | 73 FLUTE 长笛 155 | 声音柔和,做主音 156 | 74 RECORDER 竖笛 157 | TITANIC的主旋律可以用这个来做 158 | 75 PAN FLUTE 排箫 159 | 可以听到明显的呼吸声 160 | 76 BOTTLE BLOW 吹瓶声 161 | 77 SHAKUHACHI 日本尺八 162 | 明显的民族乐器,非常好听,只是GM和XG都做的不大好 163 | 78 WHISTLE 口哨声 164 | 79 OCARINA 奥卡雷那 165 | 166 | 合成主音 167 | 80 LEAD 1 (SQUARE) 合成主音1(方波) 168 | 81 LEAD 2 (SAWTOOTH) 合成主音2(锯齿波) 169 | 82 LEAD 3 (CALIOPE LEAD) 合成主音3(模拟一种吹的乐器,类似排箫) 170 | 83 LEAD 4 (CHIFF LEAD) 合成主音4(模拟一种吹的乐器) 171 | 上面几个多用于电子乐主音 172 | 84 LEAD 5 (CHARANG) 合成主音5(模拟电子失真乐器,类似失真电吉他) 173 | 可以当作电吉他使用 174 | 85 LEAD 6 (VOICE) 合成主音6(人声) 175 | 86 LEAD 7 (FIFTHS) 合成主音7(五度音) 176 | 生成一个五度音1,5不怎么用的 177 | 87 LEAD 8 (BASS+LEAD) 合成主音8(贝斯加主音) 178 | 是个合成的音色,里面有BASS音色,只适合节奏比较整齐的歌 179 | 180 | 合成音色 181 | 88 PAD 1 (NEW AGE) 合成音色1(新世纪) 182 | 89 PAD 2 (WARM) 合成音色2(温暖) 183 | 多做和弦 184 | 90 PAD 3 (POLYSYNTH) 合成音色3(多合成) 185 | 多做主音 186 | 91 PAD 4 (CHOIR) 合成音色4(合唱) 187 | 多做主旋律或者人的和声 188 | 92 PAD 5 (BOWED) 合成音色5(弓弦) 189 | 把它和BRIGHT ACCOUSTIC PIANO和STEEL GUITAR一起用会有想不到的效果 190 | 93 PAD 6 (METALLIC) 合成音色6(金属声) 191 | 94 PAD 7 (HALO) 合成音色7(光环) 192 | 95 PAD 8 (SWEEP) 合成音色8(风吹) 193 | 它不提供风吹的音效,只是声音有点像风吹,有音高的 194 | 195 | 合成效果 196 | 96 FX 1 (RAIN) 合成效果1(雨声) 197 | 97 FX 2 (SOUNDTRACK) 合成效果2(音轨) 198 | 98 FX 3 (CRYSTAL) 合成效果3(水晶) 199 | 99 FX 4 (ATMOSPHERE) 合成效果4(大气) 200 | 100 FX 5 (BRIGHTNESS) 合成效果5(明亮) 201 | 可以做分解和弦,声音很好听的,这个音色声卡不同会有很大区别 202 | 101 FX 6 (GLOBINS) 合成效果6(鬼怪) 203 | GM,XG都做的不太好,其实这个音效很好的 204 | 102 FX 7 (ECHOES) 合成效果7(回声) 205 | 103 FX 8 (SCI-FI ) 合成效果8(科幻) 206 | 207 | 民间乐器 208 | 104 SITAR 西塔尔(印度) 209 | 105 BANJO 班卓琴(美洲) 210 | 乡村音乐可以使用的 211 | 106 SHAMISEN 三昧线(日本) 212 | 忍者里面有这个乐器 213 | 107 KOTO 十三弦筝(日本) 214 | 可以当作古筝使用(独家试唱) 215 | 108 KALIMBA 卡林巴(非洲) 216 | 适合SAMBA等爵士乐 217 | 109 BAGPIPE 风笛(苏格兰) 218 | 110 FIDDLE 民族提琴 219 | 多用于乡村音乐 220 | 111 SHANAI 山奈 221 | 222 | 打击乐器 223 | 112 TINKLE BELL 叮当铃 224 | 113 AGOGO 摇摆舞铃 225 | 114 STEEL DRUMS 钢鼓 226 | 115 WOOD BLOCK 木鱼 227 | 116 TAIKO DRUM 太鼓 228 | 117 MELODIC DRUM 通通鼓 229 | 118 SYNTH DRUM 合成鼓 230 | 三种鼓都有音高的,不常用 231 | 119 REVERSE CYMBAL 铜钹 232 | 这个乐器只能延续大概三拍,(120的速度)产生一种渐强的连续敲钹效果 233 | 234 | 声音效果 235 | 120 GUITAR FRET NOISE 吉他换把杂音 236 | 121 BREATH NOISE 呼吸声 237 | 122 SEASHORE 海浪声 238 | 123 BIRD SWEET 鸟鸣 239 | 124 TELEPHONE RING 电话铃 240 | 125 HELICOPTER 直升机 241 | 126 APPLAUSE 鼓掌声 242 | 127 GUNSHOT 枪击声 243 | -------------------------------------------------------------------------------- /Source/midiplayer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace MIDIPlayer 8 | { 9 | // Pitchs 10 | // * Note 11 | // NoteBase + KeySignature -> Note 12 | // Note + Octave -> Picth 13 | // * Notation 14 | // Notation + Pitch(Note + Octave) -> Picth 15 | 16 | struct NoteBase { // 7 notes 17 | // * 'C' 'D' 'E' 'F' 'G' 'A' 'B' 18 | // * 1 2 3 4 5 6 7 19 | explicit NoteBase(uint8_t data = 0) { 20 | if ('A' <= data && data <= 'G') { 21 | if (data < 'C') 22 | this->data = (data - 'A') + 6; 23 | else 24 | this->data = (data - 'C') + 1; 25 | } 26 | else if (1 <= data && data <= 7) { 27 | this->data = data; 28 | } 29 | else { 30 | assert(false); 31 | } 32 | } 33 | uint8_t data; 34 | }; 35 | struct KeySignature { 36 | // * '\0' '#' 'b' 37 | // * 0 1 -1 38 | explicit KeySignature(int8_t data = 0) : data(data) { 39 | if (data == '#') 40 | this->data = +1; 41 | else if (data == 'b') 42 | this->data = -1; 43 | else if (data == 0) 44 | this->data = 0; 45 | else 46 | assert(false); 47 | } 48 | int8_t data; 49 | }; 50 | struct Note { // 12 + 2 notes (0 1 ~ 12 13) bC(-B) C #C(bD) D #D(bE) E(bF) F(#E) #F(bG) G #G(bA) A #A(bB) B #B(+C) 51 | explicit Note(uint8_t data) /* 0 ~ 11 : C ~ B */ : data(data + 1) { assert(data < 12); } 52 | explicit Note(NoteBase notebase) : Note(notebase, KeySignature()) {} 53 | explicit Note(NoteBase notebase, KeySignature keysignature) { 54 | static const int8_t table[] = { 1, 3, 5, 6, 8, 10, 12 }; 55 | this->data = table[notebase.data - 1] + keysignature.data; 56 | } 57 | explicit Note(const char *word) { // X bX #X Xb X# 58 | if (word[0] == 'b' || word[0] == '#') 59 | this->data = Note(NoteBase(word[1]), KeySignature(word[0])).data; 60 | else if (word[1] == 'b' || word[1] == '#') 61 | this->data = Note(NoteBase(word[0]), KeySignature(word[1])).data; 62 | else 63 | this->data = Note(NoteBase(word[0])).data; 64 | } 65 | uint8_t data; 66 | }; 67 | struct Octave { 68 | static constexpr int8_t default_octave = 4; 69 | explicit Octave(int8_t data = default_octave) : data(data) { assert(-1 <= data && data <= 9); } 70 | int8_t data; 71 | }; 72 | 73 | struct Pitch { 74 | explicit Pitch(uint8_t data) : data(data) { assert(data <= 0x7f); } 75 | Pitch(Note note) : Pitch(note, Octave()) {} 76 | Pitch(Note note, Octave octave) { 77 | // Middle C : 0x3c 78 | // C #C D #D E F #F G #G A #A B : 0xc 79 | // 1 #1 2 #2 3 4 #4 5 #5 6 #6 7 80 | this->data = note.data + 0xc - 1 + octave.data * 0xc; 81 | assert(this->data <= 0x7f); 82 | } 83 | uint8_t data; 84 | }; 85 | 86 | struct Volume { 87 | explicit Volume(uint8_t data = 0) : data(data) { assert(data <= 0x7f); } 88 | uint8_t data; 89 | }; 90 | struct Track { 91 | explicit Track(uint8_t data = 0) : data(data) { assert(data <= 0xf); } 92 | uint8_t data; 93 | }; 94 | struct Patch { 95 | explicit Patch(uint8_t data = 0) : data(data) { assert(data <= 0x7f); } 96 | uint8_t data; 97 | }; 98 | struct DeTime { 99 | explicit DeTime(uint32_t data = 0) : data(data) { assert(true); } 100 | uint32_t data; 101 | }; 102 | 103 | class Player 104 | { 105 | public: 106 | class MIDIDevice { 107 | public: 108 | MIDIDevice() : ref(nullptr, close) { open(data); } 109 | 110 | void*& get(); 111 | 112 | private: 113 | static void open(void* &data); 114 | static void close(void *data); 115 | void *data; 116 | std::shared_ptr ref; 117 | }; 118 | class TrackPlayer 119 | { 120 | public: 121 | TrackPlayer(Player &player, Track track, Volume volume) 122 | : player(player), track(track), volume(volume) {} 123 | 124 | void SetVolume(Volume volume) { 125 | this->volume = volume; 126 | } 127 | void PlayPitch(Pitch pitch) { 128 | player.PlayPitch(pitch, volume, track); 129 | } 130 | void PlayPitch(Pitch pitch, Volume volume) { 131 | player.PlayPitch(pitch, volume, track); 132 | } 133 | void PlayPitch(Pitch pitch, DeTime detime) { 134 | PlayPitch(pitch); 135 | Sleep(detime); 136 | ClosePitch(pitch); 137 | } 138 | void PlayPitch(Pitch pitch, Volume volume, DeTime detime) { 139 | PlayPitch(pitch, volume); 140 | Sleep(detime); 141 | ClosePitch(pitch); 142 | } 143 | 144 | template 145 | void PlayPitchs(Iter begin, Iter end) { 146 | for (Iter iter = begin; iter != end; ++iter) { 147 | PlayPitch(*iter); 148 | } 149 | } 150 | template 151 | void ClosePitchs(Iter begin, Iter end) { 152 | for (Iter iter = begin; iter != end; ++iter) { 153 | ClosePitch(*iter); 154 | } 155 | } 156 | template 157 | void PlayPitchs(Iter begin, Iter end, DeTime detime) { 158 | PlayPitchs(begin, end); 159 | Sleep(detime); 160 | ClosePitchs(begin, end); 161 | } 162 | 163 | void ClosePitch(Pitch pitch) { 164 | player.ClosePitch(pitch, track); 165 | } 166 | void ChangePatch(Patch patch) { 167 | player.ChangePatch(patch, track); 168 | } 169 | 170 | void Sleep(DeTime detime) { 171 | player.Sleep(detime); 172 | } 173 | 174 | private: 175 | Player & player; 176 | Track track; 177 | Volume volume; 178 | }; 179 | 180 | public: 181 | Player(); 182 | Player(const Player &); 183 | 184 | ~Player(); 185 | 186 | void PlayPitch(Pitch pitch, Volume volume, Track track) { 187 | PlayPitch(midi_device, pitch, volume, track); 188 | } 189 | void ClosePitch(Pitch pitch, Track track) { 190 | ClosePitch(midi_device, pitch, track); 191 | } 192 | void ChangePatch(Patch patch, Track track) { 193 | ChangePatch(midi_device, patch, track); 194 | } 195 | 196 | void Sleep(DeTime detime); 197 | 198 | TrackPlayer Create(Track track) { 199 | return TrackPlayer(*this, track, Volume(0x7f)); 200 | } 201 | TrackPlayer Create(Track track, Volume volume) { 202 | return TrackPlayer(*this, track, volume); 203 | } 204 | TrackPlayer Create(Track track, Volume volume, Patch patch) { 205 | TrackPlayer pc(*this, track, volume); 206 | pc.ChangePatch(patch); 207 | return pc; 208 | } 209 | TrackPlayer Create(Track track, Patch patch) { 210 | return Create(track, Volume(0x7f), patch); 211 | } 212 | TrackPlayer Create(Track track, Patch patch, Volume volume) { 213 | return Create(track, volume, patch); 214 | } 215 | 216 | public: 217 | static void PlayPitch(MIDIDevice midi_device, Pitch pitch, Volume volume, Track track); 218 | static void ClosePitch(MIDIDevice midi_device, Pitch pitch, Track track); 219 | static void ChangePatch(MIDIDevice midi_device, Patch patch, Track track); 220 | 221 | private: 222 | MIDIDevice midi_device; 223 | }; 224 | } 225 | -------------------------------------------------------------------------------- /VS2017/portsmf/portsmf.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 15.0 41 | {587F1535-A0E9-4560-B896-A4F6D2F83300} 42 | portsmf 43 | 10.0.16299.0 44 | 45 | 46 | 47 | StaticLibrary 48 | true 49 | v141 50 | MultiByte 51 | 52 | 53 | StaticLibrary 54 | false 55 | v141 56 | true 57 | MultiByte 58 | 59 | 60 | StaticLibrary 61 | true 62 | v141 63 | MultiByte 64 | 65 | 66 | StaticLibrary 67 | false 68 | v141 69 | true 70 | MultiByte 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Level3 94 | Disabled 95 | true 96 | true 97 | $(ProjectDir)..\..\ThirdLibrary\portsmf\include 98 | _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 99 | 100 | 101 | 102 | 103 | Level3 104 | Disabled 105 | true 106 | true 107 | $(ProjectDir)..\..\ThirdLibrary\portsmf\include 108 | _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 109 | 110 | 111 | 112 | 113 | Level3 114 | MaxSpeed 115 | true 116 | true 117 | true 118 | true 119 | $(ProjectDir)..\..\ThirdLibrary\portsmf\include 120 | _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 121 | 122 | 123 | true 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | MaxSpeed 131 | true 132 | true 133 | true 134 | true 135 | $(ProjectDir)..\..\ThirdLibrary\portsmf\include 136 | _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 137 | 138 | 139 | true 140 | true 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /VS2017/portmidi/portmidi.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {94247963-30D9-4118-B1C5-4B13E57F0158} 24 | portmidi 25 | 10.0.16299.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | StaticLibrary 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | StaticLibrary 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | StaticLibrary 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Level3 76 | Disabled 77 | true 78 | true 79 | $(ProjectDir)..\..\ThirdLibrary\portmidi\include 80 | _MBCS;%(PreprocessorDefinitions);WIN32;_CRT_SECURE_NO_WARNINGS 81 | 82 | 83 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);Winmm.lib 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | Level3 93 | Disabled 94 | true 95 | true 96 | $(ProjectDir)..\..\ThirdLibrary\portmidi\include 97 | _MBCS;%(PreprocessorDefinitions);WIN32;_CRT_SECURE_NO_WARNINGS 98 | 99 | 100 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);Winmm.lib 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | Level3 110 | MaxSpeed 111 | true 112 | true 113 | true 114 | true 115 | $(ProjectDir)..\..\ThirdLibrary\portmidi\include 116 | _MBCS;%(PreprocessorDefinitions);WIN32;_CRT_SECURE_NO_WARNINGS 117 | 118 | 119 | true 120 | true 121 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);Winmm.lib 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | Level3 131 | MaxSpeed 132 | true 133 | true 134 | true 135 | true 136 | $(ProjectDir)..\..\ThirdLibrary\portmidi\include 137 | _MBCS;%(PreprocessorDefinitions);WIN32;_CRT_SECURE_NO_WARNINGS 138 | 139 | 140 | true 141 | true 142 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);Winmm.lib 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /VS2017/MIDIPlayer/MIDIPlayer.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 15.0 42 | {96A564A7-0AEF-4A23-B1BE-8F5BA08B01BE} 43 | Win32Proj 44 | MIDIPlayer 45 | 10.0.16299.0 46 | 47 | 48 | 49 | Application 50 | true 51 | v141 52 | Unicode 53 | 54 | 55 | Application 56 | false 57 | v141 58 | true 59 | Unicode 60 | 61 | 62 | Application 63 | true 64 | v141 65 | Unicode 66 | 67 | 68 | Application 69 | false 70 | v141 71 | true 72 | Unicode 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | true 94 | 95 | 96 | true 97 | 98 | 99 | false 100 | 101 | 102 | false 103 | 104 | 105 | 106 | Level3 107 | Disabled 108 | true 109 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 110 | true 111 | NotUsing 112 | 113 | 114 | 115 | 116 | true 117 | Console 118 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)portmidi.lib;$(OutDir)portsmf.lib;Winmm.lib 119 | 120 | 121 | 122 | 123 | Level3 124 | Disabled 125 | true 126 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 127 | true 128 | NotUsing 129 | 130 | 131 | 132 | 133 | true 134 | Console 135 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)portmidi.lib;$(OutDir)portsmf.lib;Winmm.lib 136 | 137 | 138 | 139 | 140 | Level3 141 | MaxSpeed 142 | true 143 | true 144 | true 145 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 146 | true 147 | NotUsing 148 | 149 | 150 | 151 | 152 | true 153 | true 154 | true 155 | Console 156 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)portmidi.lib;$(OutDir)portsmf.lib;Winmm.lib 157 | 158 | 159 | 160 | 161 | Level3 162 | MaxSpeed 163 | true 164 | true 165 | true 166 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS 167 | true 168 | NotUsing 169 | 170 | 171 | 172 | 173 | true 174 | true 175 | true 176 | Console 177 | kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)portmidi.lib;$(OutDir)portsmf.lib;Winmm.lib 178 | 179 | 180 | 181 | 182 | 183 | --------------------------------------------------------------------------------