├── .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 |
--------------------------------------------------------------------------------