luup 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/luup +174 -0
- metadata +64 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 74c26b80c698a923f1276a1b2d5dafe19374d23e88be9af99db98a64bc1ebfbc
|
4
|
+
data.tar.gz: 62abcf8d3457fc26f30d8ccaf778253d0e341b3ae15cdf2e5a70b975d9755ea3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: af94e453210387c5b3641e99a6f39e3998419a2611ed9a5e12f7771adaaa1c5ecaec12b30a9b7bd7212ddfa0c55f83dc081586854c6722e8b1e9ec442a6a74bf
|
7
|
+
data.tar.gz: b63e1d8eb593720cb9b2eed6c8f60d50725e0588db6b26d10e225c0dcd32567c54315d3f666f0745c71a54ff3e9447cbb6a6bca4e58ff1c7ce232d55d89526c3
|
data/bin/luup
ADDED
@@ -0,0 +1,174 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'open3'
|
3
|
+
require 'shellwords'
|
4
|
+
require 'io/console'
|
5
|
+
require 'pathname'
|
6
|
+
require 'pulseaudio_simple_ffi'
|
7
|
+
require 'pp'
|
8
|
+
require 'readline'
|
9
|
+
|
10
|
+
Pkg='luup'
|
11
|
+
Ver='0.0.0'
|
12
|
+
ConfigDir="#{Dir.home}/.config/#{Pkg}"
|
13
|
+
Dir.mkdir(ConfigDir) unless File.directory?(ConfigDir)
|
14
|
+
|
15
|
+
Channels,Rate,WordSize=2,44100,4
|
16
|
+
FrameSize=Channels*WordSize # "frame" is all channels of a sample
|
17
|
+
BytesPerSec=Rate*FrameSize
|
18
|
+
FfmpegFmt="-ac #{Channels} -ar #{Rate} -f f#{WordSize*8}le"
|
19
|
+
Quantum=24.0 # 24 FPS = cinematic
|
20
|
+
|
21
|
+
def frame_round(x) = ( ( x.to_i / FrameSize ).to_i * FrameSize ).to_i
|
22
|
+
|
23
|
+
ChunkSize=frame_round(BytesPerSec/Quantum/2)
|
24
|
+
|
25
|
+
def readline_hooked insert,prompt
|
26
|
+
Readline.pre_input_hook = -> do
|
27
|
+
Readline.insert_text insert
|
28
|
+
Readline.redisplay
|
29
|
+
Readline.pre_input_hook=nil
|
30
|
+
end
|
31
|
+
Readline.readline prompt
|
32
|
+
end
|
33
|
+
|
34
|
+
class Luup
|
35
|
+
attr_reader :data,:pulse,:start_time,:len,:off,:out,:mode
|
36
|
+
|
37
|
+
attr_reader :len_f,:off_f,:dis_f,:num_f
|
38
|
+
attr_reader :len_byte,:off_byte,:start_byte,:curr_byte,:end_byte,:out_byte
|
39
|
+
|
40
|
+
def initialize file,len_p,off_p='0',dis_p='0',num_p='1'
|
41
|
+
fn=Shellwords.escape(file)
|
42
|
+
print "decoding #{file}..."
|
43
|
+
@data,st = Open3.capture2("ffmpeg -loglevel -8 -i #{fn} #{FfmpegFmt} -",binmode:true)
|
44
|
+
|
45
|
+
self.num=num_p
|
46
|
+
self.len=len_p
|
47
|
+
|
48
|
+
self.dis=dis_p
|
49
|
+
self.off=off_p ? off_p : `aubioquiet #{fn} | head -1 | cut -d\\ -f2`
|
50
|
+
|
51
|
+
@start_time=Time.now.to_f
|
52
|
+
@pulse=PulseAudioSimpleFFI::PulseAudioSimpleO.new(Pkg,file,channels:Channels,rate:Rate,device:@device)
|
53
|
+
@mode=:play
|
54
|
+
@curr_byte=start_byte
|
55
|
+
@out_byte=0
|
56
|
+
|
57
|
+
@out=Thread.new{
|
58
|
+
until :quit == @mode
|
59
|
+
if @curr_byte-1==end_byte
|
60
|
+
@curr_byte=start_byte
|
61
|
+
elsif frame_round( @curr_byte + ChunkSize - end_byte+1)>0
|
62
|
+
extra_byte=frame_round( @curr_byte + ChunkSize - end_byte + 1)
|
63
|
+
extra_end_byte=frame_round(start_byte+extra_byte)-1
|
64
|
+
#puts "#{curr_byte} #{end_byte} #{start_byte} #{extra_byte} #{extra_end_byte} #{chunk_size}"
|
65
|
+
@pulse.write data[@curr_byte .. end_byte]
|
66
|
+
@pulse.write data[start_byte .. extra_end_byte]
|
67
|
+
@out_byte+=(end_byte-@curr_byte+1)+(extra_end_byte-start_byte+1)
|
68
|
+
@curr_byte=extra_end_byte+1
|
69
|
+
else
|
70
|
+
@pulse.write data[@curr_byte .. @curr_byte+ChunkSize-1]
|
71
|
+
@curr_byte+=ChunkSize
|
72
|
+
@out_byte+=ChunkSize
|
73
|
+
end
|
74
|
+
wrote_t,spent_t=out_byte.to_f/BytesPerSec,Time.now.to_f-@start_time
|
75
|
+
#puts "#{wrote_t} in #{spent_t}"
|
76
|
+
sleep (wrote_t-spent_t)/Quantum if (wrote_t>spent_t)
|
77
|
+
end
|
78
|
+
@pulse.close
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
def len= x
|
83
|
+
@len=x
|
84
|
+
@len_f=x.to_f
|
85
|
+
@len_byte=frame_round(@len_f*BytesPerSec*@num_f)
|
86
|
+
end
|
87
|
+
|
88
|
+
def off= x
|
89
|
+
@off=x
|
90
|
+
@off_f=x.to_f
|
91
|
+
@off_byte=(@off_f*Rate).to_i*FrameSize + frame_round(@dis_f*@len_byte/@num_f)
|
92
|
+
end
|
93
|
+
|
94
|
+
def dis= x
|
95
|
+
@dis=x
|
96
|
+
@dis_f=x.to_f
|
97
|
+
self.off=@off if @off
|
98
|
+
end
|
99
|
+
|
100
|
+
def num= x
|
101
|
+
@num=x
|
102
|
+
@num_f=x.to_f
|
103
|
+
self.len=@len if @len
|
104
|
+
end
|
105
|
+
|
106
|
+
def start_byte
|
107
|
+
@off_byte
|
108
|
+
end
|
109
|
+
|
110
|
+
def end_byte
|
111
|
+
@off_byte + @len_byte - 1
|
112
|
+
end
|
113
|
+
|
114
|
+
def main
|
115
|
+
until :quit == @mode
|
116
|
+
d=end_byte-start_byte
|
117
|
+
c=@curr_byte-start_byte
|
118
|
+
n=(c*256/d).to_i
|
119
|
+
#msg="%0.02f" % (curr_byte.to_f/BytesPerSec)
|
120
|
+
msg="%02X" % n
|
121
|
+
print "\e[2K\r#{msg} l:#{@len} o:#{@off} n:#{@num} d:#{@dis}> "
|
122
|
+
case ch=IO.console.raw{|c|c.read_nonblock(1) rescue ''}.downcase
|
123
|
+
when 'q'
|
124
|
+
@mode=:quit
|
125
|
+
puts 'quit!'
|
126
|
+
when 'o'
|
127
|
+
new_off=readline_hooked(@off,"o:")
|
128
|
+
if(new_off.to_f!=0)
|
129
|
+
self.off=new_off
|
130
|
+
@curr_byte=start_byte
|
131
|
+
end
|
132
|
+
when 'l'
|
133
|
+
new_len=readline_hooked(@len,"l:")
|
134
|
+
if(new_len.to_f>=5 and new_len.to_f<10)
|
135
|
+
self.len=new_len
|
136
|
+
@curr_byte=start_byte
|
137
|
+
end
|
138
|
+
when 'n'
|
139
|
+
new_num=readline_hooked(@num,"n:")
|
140
|
+
if(new_num.to_f>0)
|
141
|
+
self.num=new_num
|
142
|
+
@curr_byte=start_byte
|
143
|
+
end
|
144
|
+
when 'd'
|
145
|
+
s=-(@off_f/@len_f)
|
146
|
+
l=@data.length/BytesPerSec
|
147
|
+
e=(l-@off_f)/@len_f
|
148
|
+
new_dis=readline_hooked(@dis,"d=#{"%0.03f"%(s+0.0005)}-#{"%0.03f"%(e-0.0005)}:")
|
149
|
+
if(new_dis.to_f>=s && new_dis.to_f<=e)
|
150
|
+
self.dis=new_dis
|
151
|
+
@curr_byte=start_byte
|
152
|
+
end
|
153
|
+
when ''
|
154
|
+
sleep 1/Quantum
|
155
|
+
# else
|
156
|
+
# puts 'wtf'
|
157
|
+
#print (help="#{ch} < #{list_i>0?"[P]rev ":""}[R]estart [S]eek [N]ext [Q]uit")
|
158
|
+
end
|
159
|
+
end
|
160
|
+
puts "\r ] #{Pkg} ✝ v#{Ver} [ "
|
161
|
+
@out.join
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
if ARGV.length==0
|
166
|
+
puts "Usage: #{Pkg} file"
|
167
|
+
exit 1
|
168
|
+
end
|
169
|
+
|
170
|
+
main=Luup.new(file=Pathname(ARGV[0]).realpath.to_s,'7.7948','33.125')
|
171
|
+
data=main.data
|
172
|
+
o=main.pulse
|
173
|
+
main.main
|
174
|
+
|
metadata
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: luup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Benjamin Cook
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-07-20 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pulseaudio_simple_ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.1
|
33
|
+
description: luup - a dj tool that loops music and finetunes beatgrids
|
34
|
+
email: root@baryon.it
|
35
|
+
executables:
|
36
|
+
- luup
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- bin/luup
|
41
|
+
homepage: https://github.com/Canar/luup
|
42
|
+
licenses: []
|
43
|
+
metadata: {}
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '3.0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
requirements:
|
59
|
+
- ffmpeg
|
60
|
+
rubygems_version: 3.3.15
|
61
|
+
signing_key:
|
62
|
+
specification_version: 4
|
63
|
+
summary: luup - a dj tool that loops music and finetunes beatgrids
|
64
|
+
test_files: []
|