dtas 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Documentation/GNUmakefile +2 -0
  3. data/Documentation/dtas-player_protocol.txt +28 -1
  4. data/Documentation/dtas-splitfx.txt +167 -0
  5. data/Documentation/dtas-tl.txt +77 -0
  6. data/GIT-VERSION-GEN +2 -1
  7. data/GNUmakefile +1 -1
  8. data/README +2 -1
  9. data/Rakefile +7 -0
  10. data/bin/dtas-console +11 -1
  11. data/bin/dtas-splitfx +40 -0
  12. data/bin/dtas-tl +73 -0
  13. data/examples/README +3 -0
  14. data/examples/splitfx.sample.yml +19 -0
  15. data/lib/dtas/format.rb +11 -0
  16. data/lib/dtas/pipe.rb +0 -3
  17. data/lib/dtas/player.rb +38 -11
  18. data/lib/dtas/player/client_handler.rb +94 -7
  19. data/lib/dtas/process.rb +25 -3
  20. data/lib/dtas/sink.rb +0 -3
  21. data/lib/dtas/source/sox.rb +2 -1
  22. data/lib/dtas/splitfx.rb +342 -0
  23. data/lib/dtas/tracklist.rb +130 -0
  24. data/test/helper.rb +14 -1
  25. data/test/player_integration.rb +5 -3
  26. data/test/test_buffer.rb +4 -2
  27. data/test/test_env.rb +55 -0
  28. data/test/test_format.rb +1 -1
  29. data/test/test_format_change.rb +1 -1
  30. data/test/test_player.rb +1 -1
  31. data/test/test_player_client_handler.rb +1 -1
  32. data/test/test_player_integration.rb +3 -2
  33. data/test/test_process.rb +1 -1
  34. data/test/test_rg_integration.rb +4 -5
  35. data/test/test_rg_state.rb +1 -1
  36. data/test/test_sink.rb +1 -1
  37. data/test/test_sink_pipe_size.rb +1 -1
  38. data/test/test_sink_tee_integration.rb +1 -1
  39. data/test/test_source_av.rb +1 -1
  40. data/test/test_source_sox.rb +1 -1
  41. data/test/test_splitfx.rb +79 -0
  42. data/test/test_tracklist.rb +76 -0
  43. data/test/test_unixserver.rb +1 -1
  44. data/test/test_util.rb +1 -1
  45. metadata +23 -3
data/test/helper.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  $stdout.sync = $stderr.sync = Thread.abort_on_exception = true
4
+ require 'thread'
5
+ WAIT_ALL_MTX = Mutex.new
4
6
 
5
7
  # fork-aware coverage data gatherer, see also test/covshow.rb
6
8
  if ENV["COVERAGE"]
@@ -46,13 +48,24 @@ gem 'minitest'
46
48
  require 'minitest/autorun'
47
49
  require "tempfile"
48
50
 
51
+ Testcase = begin
52
+ Minitest::Test
53
+ rescue NameError
54
+ Minitest::Unit::TestCase
55
+ end
56
+
49
57
  FIFOS = []
50
- at_exit { FIFOS.each { |(pid,path)| File.unlink(path) if $$ == pid } }
51
58
  def tmpfifo
52
59
  tmp = Tempfile.new(%w(dtas-test .fifo))
53
60
  path = tmp.path
54
61
  tmp.close!
55
62
  assert system(*%W(mkfifo #{path})), "mkfifo #{path}"
63
+
64
+ if FIFOS.empty?
65
+ at_exit do
66
+ FIFOS.each { |(pid,_path)| File.unlink(_path) if $$ == pid }
67
+ end
68
+ end
56
69
  FIFOS << [ $$, path ]
57
70
  path
58
71
  end
@@ -74,8 +74,10 @@ module PlayerIntegration
74
74
  end
75
75
 
76
76
  def teardown
77
- Process.kill(:TERM, @pid) if @pid
78
- Process.waitall
77
+ if @pid
78
+ Process.kill(:TERM, @pid)
79
+ Process.waitpid2(@pid)
80
+ end
79
81
  refute File.exist?(@sock_path)
80
82
  @state_tmp.close!
81
83
  @out.close! if @out
@@ -92,7 +94,7 @@ module PlayerIntegration
92
94
  def tmp_noise(len = 5)
93
95
  noise = Tempfile.open(%w(junk .sox))
94
96
  cmd = %W(sox -R -n -r44100 -c2 #{noise.path} synth #{len} pluck)
95
- assert system(*cmd), cmd
97
+ assert system(*cmd), cmd.inspect
96
98
  [ noise, len ]
97
99
  end
98
100
 
data/test/test_buffer.rb CHANGED
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'stringio'
5
5
  require 'dtas/buffer'
6
6
 
7
- class TestBuffer < Minitest::Unit::TestCase
7
+ class TestBuffer < Testcase
8
8
  def teardown
9
9
  @to_close.each { |io| io.close unless io.closed? }
10
10
  end
@@ -118,6 +118,8 @@ class TestBuffer < Minitest::Unit::TestCase
118
118
  assert_equal :wait_readable, buf.broadcast([a[1], b[1]])
119
119
  assert_equal 5, buf.bytes_xfer
120
120
 
121
+ return unless b[1].respond_to?(:pipe_size)
122
+
121
123
  b[1].nonblock = true
122
124
  b[1].write('*' * b[1].pipe_size)
123
125
  buf.wr.write "BYE"
@@ -175,7 +177,7 @@ class TestBuffer < Minitest::Unit::TestCase
175
177
  buf.wr.write "HELLO"
176
178
  assert_equal tmp, buf.broadcast(tmp)
177
179
  assert_equal [a[1], b[1]], tmp
178
- end
180
+ end if IO.method_defined?(:pipe_size)
179
181
 
180
182
  def test_serialize
181
183
  buf = new_buffer
data/test/test_env.rb ADDED
@@ -0,0 +1,55 @@
1
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ require_relative 'helper'
4
+ require 'dtas/process'
5
+ class TestEnv < Testcase
6
+ include DTAS::Process
7
+ def setup
8
+ @orig = ENV.to_hash
9
+ end
10
+
11
+ def teardown
12
+ ENV.clear
13
+ ENV.update(@orig)
14
+ end
15
+
16
+ def test_expand
17
+ ENV["HELLO"] = 'HIHI'
18
+ expect = { "BLAH" => "HIHI/WORLD" }
19
+ opts = {}
20
+
21
+ env = { "BLAH" => "$HELLO/WORLD" }
22
+ assert_equal(expect, env_expand(env, opts))
23
+
24
+ env = { "BLAH" => "${HELLO}/WORLD" }
25
+ assert_equal(expect, env_expand(env, opts))
26
+
27
+ env = { "BLAH" => "$(echo $HELLO)/WORLD" }
28
+ assert_equal(expect, env_expand(env, opts))
29
+
30
+ env = { "BLAH" => "`echo $HELLO/WORLD`" }
31
+ assert_equal(expect, env_expand(env, opts))
32
+
33
+ env = { "BLAH" => "HIHI/WORLD" }
34
+ assert_equal(expect, env_expand(env, opts))
35
+
36
+ # disable expansion
37
+ env = expect = { "BLAH" => "`echo $HELLO/WORLD`" }
38
+ assert_equal(expect, env_expand(env, expand: false))
39
+
40
+ # numeric expansion always happens
41
+ env = { "BLAH" => 1 }
42
+ assert_equal({"BLAH"=>"1"}, env_expand(env, expand: false))
43
+ env = { "BLAH" => 1 }
44
+ assert_equal({"BLAH"=>"1"}, env_expand(env, {}))
45
+
46
+ expect = { "BLAH" => nil }
47
+ env = expect.dup
48
+ assert_equal expect, env_expand(env, expand:false)
49
+ assert_equal expect, env_expand(env, expand:true)
50
+
51
+ # recursive expansion
52
+ res = env_expand({"PATH"=>"$PATH"}, expand: true)
53
+ assert_equal ENV["PATH"], res["PATH"]
54
+ end
55
+ end
data/test/test_format.rb CHANGED
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'tempfile'
5
5
  require 'dtas/format'
6
6
 
7
- class TestFormat < Minitest::Unit::TestCase
7
+ class TestFormat < Testcase
8
8
  def test_initialize
9
9
  fmt = DTAS::Format.new
10
10
  assert_equal %w(-ts32 -c2 -r44100), fmt.to_sox_arg
@@ -2,7 +2,7 @@
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  require './test/player_integration'
4
4
  require 'tmpdir'
5
- class TestFormatChange < Minitest::Unit::TestCase
5
+ class TestFormatChange < Testcase
6
6
  include PlayerIntegration
7
7
 
8
8
  def test_format_change
data/test/test_player.rb CHANGED
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'tempfile'
5
5
  require 'dtas/player'
6
6
 
7
- class TestPlayer < Minitest::Unit::TestCase
7
+ class TestPlayer < Testcase
8
8
  def setup
9
9
  @player = nil
10
10
  tmp = Tempfile.new(%w(dtas-player-test .sock))
@@ -3,7 +3,7 @@
3
3
  require './test/helper'
4
4
  require 'dtas/player'
5
5
 
6
- class TestPlayerClientHandler < Minitest::Unit::TestCase
6
+ class TestPlayerClientHandler < Testcase
7
7
  class MockIO < Array
8
8
  alias emit push
9
9
  end
@@ -1,7 +1,7 @@
1
1
  # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  require './test/player_integration'
4
- class TestPlayerIntegration < Minitest::Unit::TestCase
4
+ class TestPlayerIntegration < Testcase
5
5
  include PlayerIntegration
6
6
 
7
7
  def test_cmd_rate
@@ -124,7 +124,8 @@ class TestPlayerIntegration < Minitest::Unit::TestCase
124
124
  def test_sink_env
125
125
  s = client_socket
126
126
  tmp = Tempfile.new(%w(env .txt))
127
- s.req_ok("sink ed default active=true command='echo -$FOO- > #{tmp.path}'")
127
+ s.req_ok("sink ed default active=true " \
128
+ "command='echo -$FOO- > #{tmp.path}; cat >/dev/null'")
128
129
 
129
130
  s.req_ok("sink ed default env.FOO=BAR")
130
131
  s.req_ok(["enq-cmd", "echo HI"])
data/test/test_process.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  require './test/helper'
4
4
  require 'dtas/process'
5
- class TestProcess < Minitest::Unit::TestCase
5
+ class TestProcess < Testcase
6
6
  include DTAS::Process
7
7
 
8
8
  def test_encoding
@@ -1,20 +1,20 @@
1
1
  # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  require './test/player_integration'
4
- class TestRgIntegration < Minitest::Unit::TestCase
4
+ class TestRgIntegration < Testcase
5
5
  include PlayerIntegration
6
6
 
7
7
  def tmp_pluck(len = 5)
8
8
  pluck = Tempfile.open(%w(pluck .flac))
9
9
  cmd = %W(sox -R -n -r44100 -c2 -C0 #{pluck.path} synth #{len} pluck)
10
- assert system(*cmd), cmd
10
+ assert system(*cmd), cmd.inspect
11
11
  cmd = %W(metaflac
12
12
  --set-tag=REPLAYGAIN_TRACK_GAIN=-2
13
13
  --set-tag=REPLAYGAIN_ALBUM_GAIN=-3.0
14
14
  --set-tag=REPLAYGAIN_TRACK_PEAK=0.666
15
15
  --set-tag=REPLAYGAIN_ALBUM_PEAK=0.999
16
16
  #{pluck.path})
17
- assert system(*cmd), cmd
17
+ assert system(*cmd), cmd.inspect
18
18
  [ pluck, len ]
19
19
  end
20
20
 
@@ -40,7 +40,7 @@ class TestRgIntegration < Minitest::Unit::TestCase
40
40
  end while cur["current_offset"] == 0 && sleep(0.01)
41
41
  end
42
42
 
43
- assert_empty cur["current"]["env"]["RGFX"]
43
+ assert_nil cur["current"]["env"]["RGFX"]
44
44
 
45
45
  assert_equal DTAS::Format.new.rate * len, cur["current_expect"]
46
46
 
@@ -119,7 +119,6 @@ class TestRgIntegration < Minitest::Unit::TestCase
119
119
  "REPLAYGAIN_ALBUM_GAIN" => "-3.0",
120
120
  "REPLAYGAIN_TRACK_PEAK" => "0.666",
121
121
  "REPLAYGAIN_ALBUM_PEAK" => "0.999",
122
- "REPLAYGAIN_REFERENCE_LOUDNESS" => nil
123
122
  }
124
123
  assert_equal expect, rg
125
124
  end
@@ -3,7 +3,7 @@
3
3
  require './test/helper'
4
4
  require 'dtas/rg_state'
5
5
 
6
- class TestRGState < Minitest::Unit::TestCase
6
+ class TestRGState < Testcase
7
7
 
8
8
  def test_rg_state
9
9
  rg = DTAS::RGState.new
data/test/test_sink.rb CHANGED
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'dtas/sink'
5
5
  require 'yaml'
6
6
 
7
- class TestSink < Minitest::Unit::TestCase
7
+ class TestSink < Testcase
8
8
  def test_serialize_reload
9
9
  sink = DTAS::Sink.new
10
10
  sink.name = "DAC"
@@ -3,7 +3,7 @@
3
3
  begin
4
4
  require 'io/splice'
5
5
  require './test/player_integration'
6
- class TestSinkPipeSizeIntegration < Minitest::Unit::TestCase
6
+ class TestSinkPipeSizeIntegration < Testcase
7
7
  include PlayerIntegration
8
8
 
9
9
  def test_sink_pipe_size_integration
@@ -1,7 +1,7 @@
1
1
  # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
2
  # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
3
  require './test/player_integration'
4
- class TestSinkTeeIntegration < Minitest::Unit::TestCase
4
+ class TestSinkTeeIntegration < Testcase
5
5
  include PlayerIntegration
6
6
 
7
7
  def test_tee_integration
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'dtas/source/av'
5
5
  require 'tempfile'
6
6
 
7
- class TestSourceAv < Minitest::Unit::TestCase
7
+ class TestSourceAv < Testcase
8
8
  def teardown
9
9
  @tempfiles.each { |tmp| tmp.close! }
10
10
  end
@@ -4,7 +4,7 @@ require './test/helper'
4
4
  require 'dtas/source/sox'
5
5
  require 'tempfile'
6
6
 
7
- class TestSource < Minitest::Unit::TestCase
7
+ class TestSource < Testcase
8
8
  def teardown
9
9
  @tempfiles.each { |tmp| tmp.close! }
10
10
  end
@@ -0,0 +1,79 @@
1
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ require 'yaml'
4
+ require 'dtas/splitfx'
5
+ require 'thread'
6
+ require_relative 'helper'
7
+
8
+ class TestSplitfx < Testcase
9
+ def test_t2s
10
+ sfx = DTAS::SplitFX.new
11
+ sfx.instance_eval do
12
+ @infmt = DTAS::Format.load("rate"=>44100)
13
+ end
14
+ assert_equal 118554000, sfx.t2s_cdda('44:48.3')
15
+ assert_equal 118554030, sfx.t2s('44:48.3')
16
+ end
17
+
18
+ def test_example
19
+ hash = YAML.load(File.read("examples/splitfx.sample.yml"))
20
+ sfx = DTAS::SplitFX.new
21
+ Dir.mktmpdir do |dir|
22
+ Dir.chdir(dir) do
23
+ # create a guitar pluck
24
+ cmd = '(for n in E2 A2 D3 G3 B3 E4; do '\
25
+ 'sox -n -ts32 -c2 -r44100 - synth 4 pluck $n; done ) | ' \
26
+ 'sox -ts32 -c2 -r44100 - foo.flac'
27
+ assert system(cmd), cmd.inspect
28
+ sfx.import(hash, {})
29
+ opts = { jobs: nil, silent: true }
30
+
31
+ # ensure default FLAC target works
32
+ WAIT_ALL_MTX.synchronize { sfx.run("flac", opts) }
33
+ expect = %w(1.flac 2.flac foo.flac)
34
+ assert_equal expect, Dir["*.flac"].sort
35
+
36
+ # compare results with expected output
37
+ res_cmd = "sox 1.flac 2.flac -ts32 -c2 -r44100 result.s32"
38
+ res_pid = fork { exec res_cmd }
39
+ exp_cmd = "sox foo.flac -ts32 -c2 -r44100 expect.s32 trim 4"
40
+ exp_pid = fork { exec exp_cmd }
41
+ _, s = Process.waitpid2(res_pid)
42
+ assert s.success?, "#{res_cmd}: #{s.inspect}"
43
+ _, s = Process.waitpid2(exp_pid)
44
+ assert s.success?, "#{exp_cmd}: #{s.inspect}"
45
+ cmp = "cmp result.s32 expect.s32"
46
+ assert system(cmp), cmp
47
+
48
+ # try Ogg Opus, use opusenc/opusdec for now since that's available
49
+ # in Debian 7.0 (sox.git currently has opusfile support, but that
50
+ # hasn't made it into Debian, yet)
51
+ if `which opusenc 2>/dev/null`.size > 0 &&
52
+ `which opusdec 2>/dev/null`.size > 0
53
+ err = $stderr.dup
54
+ begin
55
+ $stderr.reopen("/dev/null", "a")
56
+ WAIT_ALL_MTX.synchronize { sfx.run("opusenc", opts) }
57
+ ensure
58
+ $stderr.reopen(err)
59
+ end
60
+
61
+ # ensure opus lengths match flac ones, we decode using opusdec
62
+ # since sox does not yet have opus support in Debian 7.0
63
+ %w(1 2).each do |nr|
64
+ cmd = "opusdec #{nr}.opus #{nr}.wav 2>/dev/null"
65
+ assert system(cmd), cmd
66
+ assert_equal `soxi -D #{nr}.flac`, `soxi -D #{nr}.wav`
67
+ end
68
+ end
69
+
70
+ # ensure 16/44.1kHz FLAC works (CDDA-like)
71
+ File.unlink('1.flac', '2.flac')
72
+ WAIT_ALL_MTX.synchronize { sfx.run("flac-cdda", opts) }
73
+ %w(1 2).each do |nr|
74
+ assert_equal `soxi -D #{nr}.flac`, `soxi -D #{nr}.wav`
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,76 @@
1
+ # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
2
+ # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
3
+ require_relative 'helper'
4
+ require 'dtas/tracklist'
5
+ class TestTracklist < Testcase
6
+ def test_tl_add_tracks
7
+ tl = DTAS::Tracklist.new
8
+ tl.add_track("/foo.flac")
9
+ assert_equal(%w(/foo.flac), tl.instance_variable_get(:@list))
10
+
11
+ oids = tl.tracks
12
+ assert_kind_of Array, oids
13
+ assert_equal 1, oids.size
14
+ assert_equal [ [ oids[0], "/foo.flac" ] ], tl.get_tracks(oids)
15
+
16
+ tl.add_track("/bar.flac")
17
+ assert_equal(%w(/bar.flac /foo.flac), tl.instance_variable_get(:@list))
18
+
19
+ tl.add_track("/after.flac", oids[0])
20
+ assert_equal(%w(/bar.flac /foo.flac /after.flac),
21
+ tl.instance_variable_get(:@list))
22
+ end
23
+
24
+ def test_add_current
25
+ tl = DTAS::Tracklist.new
26
+ tl.instance_variable_get(:@list).replace(%w(a b c d e f g))
27
+ tl.add_track('/foo.flac', nil, true)
28
+ assert_equal '/foo.flac', tl.cur_track
29
+ end
30
+
31
+ def test_advance_track
32
+ tl = DTAS::Tracklist.new
33
+ tl.instance_variable_get(:@list).replace(%w(a b c d e f g))
34
+ %w(a b c d e f g).each do |t|
35
+ assert_equal t, tl.advance_track[0]
36
+ end
37
+ assert_nil tl.advance_track
38
+ tl.repeat = true
39
+ assert_equal 'a', tl.advance_track[0]
40
+ end
41
+
42
+ def _build_mapping(tl)
43
+ tracks = tl.get_tracks(tl.tracks)
44
+ Hash[tracks.map { |(oid,name)| [ name, oid ] }]
45
+ end
46
+
47
+ def test_goto
48
+ tl = DTAS::Tracklist.new
49
+ tl.instance_variable_get(:@list).replace(%w(a b c d e f g))
50
+ mapping = _build_mapping(tl)
51
+ assert_equal 'f', tl.go_to(mapping['f'])
52
+ assert_equal 'f', tl.advance_track[0]
53
+ assert_nil tl.go_to(1 << 128)
54
+ assert_equal 'g', tl.advance_track[0]
55
+ end
56
+
57
+ def test_remove_track
58
+ tl = DTAS::Tracklist.new
59
+ tl.instance_variable_get(:@list).replace(%w(a b c d e f g))
60
+ mapping = _build_mapping(tl)
61
+ %w(a b c d e f g).each { |t| assert_kind_of Integer, mapping[t] }
62
+
63
+ tl.remove_track(mapping['a'])
64
+ assert_equal %w(b c d e f g), tl.instance_variable_get(:@list)
65
+
66
+ tl.remove_track(mapping['d'])
67
+ assert_equal %w(b c e f g), tl.instance_variable_get(:@list)
68
+
69
+ tl.remove_track(mapping['g'])
70
+ assert_equal %w(b c e f), tl.instance_variable_get(:@list)
71
+
72
+ # it'll be a while before OIDs require >128 bits, right?
73
+ tl.remove_track(1 << 128)
74
+ assert_equal %w(b c e f), tl.instance_variable_get(:@list), "no change"
75
+ end
76
+ end