Init repository.

This commit is contained in:
Pim Kunis 2020-10-10 19:36:07 +02:00
commit 39f5f592a7
9 changed files with 191 additions and 0 deletions

4
.formatter.exs Normal file
View file

@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

24
.gitignore vendored Normal file
View file

@ -0,0 +1,24 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
midi_tools-*.tar

21
README.md Normal file
View file

@ -0,0 +1,21 @@
# MIDITools
**TODO: Add description**
## Installation
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `midi_tools` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:midi_tools, "~> 0.1.0"}
]
end
```
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/midi_tools](https://hexdocs.pm/midi_tools).

18
lib/midi_tools.ex Normal file
View file

@ -0,0 +1,18 @@
defmodule MIDITools do
@moduledoc """
Documentation for `MIDITools`.
"""
@doc """
Hello world.
## Examples
iex> MIDITools.hello()
:world
"""
def hello do
:world
end
end

73
lib/midi_tools/player.ex Normal file
View file

@ -0,0 +1,73 @@
defmodule Player do
use GenServer
# Client API
def start_link(arg \\ nil) do
GenServer.start_link(__MODULE__, arg, name: __MODULE__)
end
def set_schedule(schedule) do
GenServer.call(__MODULE__, {:set_schedule, schedule})
end
def play do
GenServer.call(__MODULE__, :play)
end
# Server callbacks
@impl true
def init(_arg) do
{:ok, synth} = MIDISynth.start_link([])
epoch = Timex.epoch() |> Timex.to_datetime()
{:ok, %{timer: nil, schedule: [], schedule_left: [], start_time: epoch, synth: synth}}
end
@impl true
def handle_call({:set_schedule, schedule}, _from, state) do
{:reply, :ok, %{state | schedule: schedule, schedule_left: schedule}}
end
def handle_call(:play, _from, %{schedule_left: schedule_left} = state) do
start_time = Timex.now()
state = %{state | start_time: start_time}
timer = start_timer(schedule_left, start_time)
{:reply, :ok, %{state | timer: timer}}
end
@impl true
def handle_info(
:play,
%{schedule_left: schedule_left, start_time: start_time, synth: synth} = state
) do
schedule_left = play_next_midi(schedule_left, start_time, synth)
{:noreply, %{state | schedule_left: schedule_left}}
end
defp play_next_midi([], _start_time, _synth), do: []
defp play_next_midi([{offset, command} | next_schedule] = schedule_left, start_time, synth) do
next_time = DateTime.add(start_time, offset, :millisecond)
micro_diff = Timex.diff(next_time, Timex.now(), :microsecond)
if micro_diff < 500 do
# Play command, and try to play next command too.
MIDISynth.midi(synth, command)
play_next_midi(next_schedule, start_time, synth)
else
# Command is too far in the future, schedule next timer.
delay = ceil(micro_diff / 1000)
Process.send_after(self(), :play, delay)
schedule_left
end
end
defp start_timer([], _start_time), do: nil
defp start_timer([{offset, _command} | _], start_time) do
next_time = DateTime.add(start_time, offset, :millisecond)
delay = Timex.diff(next_time, Timex.now(), :millisecond)
Process.send_after(self(), :play, delay)
end
end

26
mix.exs Normal file
View file

@ -0,0 +1,26 @@
defmodule MIDITools.MixProject do
use Mix.Project
def project do
[
app: :midi_tools,
version: "0.1.0",
elixir: "~> 1.10",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
def application do
[
extra_applications: [:logger]
]
end
defp deps do
[
{:midi_synth, "~> 0.4.0"},
{:timex, "~> 3.6"}
]
end
end

16
mix.lock Normal file
View file

@ -0,0 +1,16 @@
%{
"certifi": {:hex, :certifi, "2.5.2", "b7cfeae9d2ed395695dd8201c57a2d019c0c43ecaf8b8bcb9320b40d6662f340", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "3b3b5f36493004ac3455966991eaf6e768ce9884693d9968055aeeeb1e575040"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
"elixir_make": {:hex, :elixir_make, "0.6.1", "8faa29a5597faba999aeeb72bbb9c91694ef8068f0131192fb199f98d32994ef", [:mix], [], "hexpm", "35d33270680f8d839a4003c3e9f43afb595310a592405a00afc12de4c7f55a18"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"},
"hackney": {:hex, :hackney, "1.16.0", "5096ac8e823e3a441477b2d187e30dd3fff1a82991a806b2003845ce72ce2d84", [:rebar3], [{:certifi, "2.5.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.1", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.0", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.6", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3bf0bebbd5d3092a3543b783bf065165fa5d3ad4b899b836810e513064134e18"},
"idna": {:hex, :idna, "6.0.1", "1d038fb2e7668ce41fbf681d2c45902e52b3cb9e9c77b55334353b222c2ee50c", [:rebar3], [{:unicode_util_compat, "0.5.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a02c8a1c4fd601215bb0b0324c8a6986749f807ce35f25449ec9e69758708122"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"midi_synth": {:hex, :midi_synth, "0.4.0", "58e88aee3fdaf4f60e99847fdbf8921576dce5820966f0d58a4c0f4a96198740", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "789152ba66603e5c358c7f6971ceac6f014e7605e2367cc6be7a9af36fc2cc70"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"timex": {:hex, :timex, "3.6.2", "845cdeb6119e2fef10751c0b247b6c59d86d78554c83f78db612e3290f819bc2", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5 or ~> 1.0.0", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm", "26030b46199d02a590be61c2394b37ea25a3664c02fafbeca0b24c972025d47a"},
"tzdata": {:hex, :tzdata, "1.0.4", "a3baa4709ea8dba552dca165af6ae97c624a2d6ac14bd265165eaa8e8af94af6", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "b02637db3df1fd66dd2d3c4f194a81633d0e4b44308d36c1b2fdfd1e4e6f169b"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.5.0", "8516502659002cec19e244ebd90d312183064be95025a319a6c7e89f4bccd65b", [:rebar3], [], "hexpm", "d48d002e15f5cc105a696cf2f1bbb3fc72b4b770a184d8420c8db20da2674b38"},
}

8
test/midi_tools_test.exs Normal file
View file

@ -0,0 +1,8 @@
defmodule MIDIToolsTest do
use ExUnit.Case
doctest MIDITools
test "greets the world" do
assert MIDITools.hello() == :world
end
end

1
test/test_helper.exs Normal file
View file

@ -0,0 +1 @@
ExUnit.start()