diff --git a/.gitignore b/.gitignore index b0347e7..99018e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /midi-parser +/build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..e9a5e22 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,19 @@ + +cmake_minimum_required(VERSION 3.30) + +project(midi-parser) + +set(CMAKE_CXX_STANDARD 26) +set(CMAKE_CXX_FLAGS "-g") + +set(SRCS + src/main.cpp + src/device.cpp + src/key.cpp +) + +add_subdirectory(midifile) +add_executable(midi-parser ${SRCS}) + +target_link_libraries(midi-parser PRIVATE midifile PUBLIC stdc++) + diff --git a/build.sh b/build.sh deleted file mode 100755 index 7bab46c..0000000 --- a/build.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -cd midifile && cmake . && make && cd .. - -g++ src/main.cpp ./midifile/libmidifile.a -o midi-parser -g -O3 - diff --git a/src/device.cpp b/src/device.cpp new file mode 100644 index 0000000..9170ba4 --- /dev/null +++ b/src/device.cpp @@ -0,0 +1,41 @@ + +#include "device.hpp" + +#include +#include +#include + +Device::Device(const char* path) { + fd = ::open(path, O_RDWR); +} + +Device::~Device() { + ::close(fd); +} + +Device::operator int() { + return fd; +} + +void Device::print(const char* data) { + for(size_t i = 0; data[i] != '\0'; i++) { + ::write(fd, &data[i], 1); + } +} + +void Device::write(const char* data, size_t len) { + ::write(fd, data, len); +} + +void Device::read(char* data, size_t len) { + ::read(fd, data, len); +} + +void Device::read_until(char target) { + char ch; + read(&ch, 1); + while(ch != target) { + read(&ch, 1); + } +} + diff --git a/src/device.hpp b/src/device.hpp new file mode 100644 index 0000000..eadfae4 --- /dev/null +++ b/src/device.hpp @@ -0,0 +1,26 @@ + +#pragma once + +#include +#include + +struct Device { + Device(const char* path); + ~Device(); + operator int(); + void print(const char* data); + void write(const char* data, size_t len); + void read(char* data, size_t len); + void read_until(char target = '\n'); + + template + void printf(const char* format, Args... args) { + char buff[1024]; + size_t len = std::snprintf(buff, sizeof(buff), format, args...); + write(buff, len); + } + +private: + int fd; +}; + diff --git a/src/key.cpp b/src/key.cpp new file mode 100644 index 0000000..8836332 --- /dev/null +++ b/src/key.cpp @@ -0,0 +1,12 @@ + +#include "key.hpp" +#include +#include + +const double KEYS[] = {16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87}; + +int key::get_freq(int key) { + int octave = key / std::size(KEYS); + return (int)std::round(KEYS[key % std::size(KEYS)] * std::pow(2, octave)); +} + diff --git a/src/key.hpp b/src/key.hpp new file mode 100644 index 0000000..7db4cd1 --- /dev/null +++ b/src/key.hpp @@ -0,0 +1,8 @@ + +#pragma once + +namespace key { + + int get_freq(int key); +}; + diff --git a/src/main.cpp b/src/main.cpp index e665a68..82e3f0c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,34 +3,14 @@ #include #include #include -#include -#include #include -#include #include -#include #include -#include -#include - -const double KEYS[] = {16.35, 17.32, 18.35, 19.45, 20.6, 21.83, 23.12, 24.5, 25.96, 27.5, 29.14, 30.87}; - -double get_key_freq(int key) { - int octave = key / std::size(KEYS); - return KEYS[key % std::size(KEYS)] * std::pow(2, octave); -} - -volatile std::sig_atomic_t running = true; - -void signal_handler(int id) { - std::cout << "Quitting\n"; - running = false; -} +#include "device.hpp" +#include "key.hpp" int main(int argc, char** argv) { - std::signal(SIGINT, signal_handler); - smf::MidiFile midifile; midifile.read(argv[2]); @@ -54,16 +34,14 @@ int main(int argc, char** argv) { midifile.doTimeAnalysis(); midifile.joinTracks(); - std::ofstream device {argv[1], std::ios::binary}; - device << ":c,"; - device.flush(); + Device device(argv[1]); auto& track = midifile[0]; int current_pressed_keys = 0; int max_pressed_keys = 0; double time_end = 0; - for(int i = 0; i < track.size() && running; i++) { + for(int i = 0; i < track.size(); i++) { smf::MidiEvent& event = track[i]; if(!event.isNote()) { @@ -89,11 +67,15 @@ int main(int argc, char** argv) { } } - double amplitude = 1.0 / max_pressed_keys; + int tones_total = 0; + double amplitude = std::max(1.0 / max_pressed_keys, 1.0/16.0); std::vector channel_key_nums(max_pressed_keys, -1); - auto now = std::chrono::high_resolution_clock::now(); - for(int i = 0; i < track.size() && running; i++) { + std::cout << "Seconds per tick: " << midifile.getTimeInSeconds(1) << std::endl; + + device.printf(":w,o,%f,%d,", amplitude, (int)(midifile.getTimeInSeconds(1) * 1000000)); + + for(int i = 0; i < track.size(); i++) { smf::MidiEvent& event = track[i]; if(!event.isNote()) { @@ -134,18 +116,14 @@ int main(int argc, char** argv) { } end: - double key_freq = get_key_freq(key); - - std::this_thread::sleep_until(now + std::chrono::duration(event.seconds)); - device << ":s," << channel << "," << key_freq << ','; + int key_freq = key::get_freq(key); + device.read_until(); if(event.isNoteOn()) { - device << std::max(amplitude, 1.0/16.0); + device.printf("s,%d,%d,%d,", event.tick, channel, key_freq); } else { - device << '0'; + device.printf("c,%d,%d,", event.tick, channel); } - device << ','; - device.flush(); if(i < track.size() - 1 && event.seconds == track[i + 1].seconds) { continue; @@ -169,13 +147,15 @@ end: } } - std::cout << " + " << event.seconds << "s / " << time_end << "s" << std::endl; + std::cout << " + " << event.seconds << "s / " << time_end << 's' << std::endl; + tones_total++; } - device << ":c,"; - device.flush(); + device.read_until(); + device.printf(";,:p,"); + + std::cout << "Sent " << tones_total << " tones\n"; return 0; } -