vissen-output 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # The pixel buffer is an implementation of the general `Buffer` module that
6
+ # places `Pixel` objects in each buffer element.
7
+ class PixelBuffer
8
+ include Buffer
9
+
10
+ # @!method pixels
11
+ # @return [Pixel] the pixels in the buffer.
12
+ alias pixels elements
13
+
14
+ # @raise [ContextError] if any of the filters does not share the same
15
+ # context.
16
+ #
17
+ # @param context [Context] the context in which the pixel buffer exists.
18
+ # @param filters [Array<Filter>] the output filters to apply when
19
+ # finalizing the buffer.
20
+ def initialize(context, filters = [])
21
+ super context, Pixel
22
+ # Verify that all filters share the same context
23
+ # before adding them.
24
+ filters.each { |f| raise ContextError unless share_context? f }
25
+ @filters = filters
26
+
27
+ freeze
28
+ end
29
+
30
+ # Prevent any more filters from being added.
31
+ #
32
+ # @return [self]
33
+ def freeze
34
+ @filters.freeze
35
+ super
36
+ end
37
+
38
+ # Zeros the RGB components of each pixel in the buffer.
39
+ def clear!
40
+ pixels.each(&:clear!)
41
+ end
42
+
43
+ # Replaces the pixel values of this buffer with those of the given object.
44
+ #
45
+ # @raise [TypeError] if the other object is not a PixelBuffer.
46
+ #
47
+ # @param other [PixelBuffer] the pixel buffer to copy values from.
48
+ def copy!(other)
49
+ raise TypeError unless other.is_a? self.class
50
+
51
+ other.each_with_index do |src_pixel, index|
52
+ dst_pixel = pixels[index]
53
+
54
+ dst_pixel.r = src_pixel.r
55
+ dst_pixel.g = src_pixel.g
56
+ dst_pixel.b = src_pixel.b
57
+ end
58
+ end
59
+
60
+ # Signals to the `PixelBuffer` that the user is done updating the color
61
+ # values and that the buffer should perform any post processing that is
62
+ # needed.
63
+ #
64
+ # @return [self]
65
+ def finalize!
66
+ @filters.each { |filter| filter.apply self }
67
+ self
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # Points are simple two dimensional coordinates with an x and y component.
6
+ # They are used by the `CloudContext` to keep track of the position of its
7
+ # points.
8
+ class Point
9
+ # @return [Array<Float>] an array containing the x and y coordinates of
10
+ # the point.
11
+ attr_reader :position
12
+
13
+ alias to_a position
14
+
15
+ # @param x [Numeric] the x coordinate of the point.
16
+ # @param y [Numeric] the y coordinate of the point.
17
+ # @param scale [Numeric] a scale factor to apply to the coordinates.
18
+ def initialize(x, y, scale: 1.0)
19
+ @position = [x * scale, y * scale]
20
+ end
21
+
22
+ # @return [Float] the x coordinate of the point.
23
+ def x
24
+ @position[0]
25
+ end
26
+
27
+ # @return [Float] the y coordinate of the point.
28
+ def y
29
+ @position[1]
30
+ end
31
+
32
+ # Prevents the position from being changed.
33
+ #
34
+ # @return [self]
35
+ def freeze
36
+ @position.freeze
37
+ super
38
+ end
39
+
40
+ # @return [String] a string representation of the point.
41
+ def inspect
42
+ format('(%0.2f,%0.2f)', *@position)
43
+ end
44
+
45
+ class << self
46
+ # Coerce objects into points.
47
+ #
48
+ # @param obj [#to_a] the object to be coerced into a `Point`.
49
+ # @param args (see #initialize)
50
+ # @return [Point] a new `Point` object.
51
+ def from(obj, **args)
52
+ new(*obj.to_a, **args)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # The Vissen Output library version number.
6
+ VERSION = '0.6.1'
7
+ end
8
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # The `Vixel` (Vissen pixel) represents the two dimensional representation
6
+ # of each grid pixel, for each grid. Each vixel has an intensity (i) and a
7
+ # palette position (p), both with values in the range 0..1.
8
+ #
9
+ # TODO: How do we want the vixel to saturate? When written or when read?
10
+ class Vixel
11
+ # @return [Float] the vixel intensity.
12
+ attr_reader :i
13
+
14
+ # @return [Float] the vixel palette position.
15
+ attr_reader :p
16
+
17
+ # @param i [Numeric] the vixel intensity.
18
+ # @param p [Numeric] the vixel palette position.
19
+ def initialize(i = 0.0, p = 0.0)
20
+ self.i = i
21
+ self.p = p
22
+ end
23
+
24
+ # @param other [Object] the object to check equality against.
25
+ # @return [true,false] true if the other object has the same intensity and
26
+ # palette position.
27
+ def ==(other)
28
+ @i == other.i && @p == other.p
29
+ rescue NoMethodError
30
+ false
31
+ end
32
+
33
+ # @param value [Numeric] the new intensity value.
34
+ # @return [Float] the truncated intensity value.
35
+ def i=(value)
36
+ @i = self.class.truncate value
37
+ end
38
+
39
+ # @param value [Numeric] the new palette position.
40
+ # @return [Float] the truncated palette position.
41
+ def p=(value)
42
+ @p = self.class.truncate value
43
+ end
44
+
45
+ # @return [String] a string representation of the vixel.
46
+ def inspect
47
+ format '(%.1f, %.1f)', @i, @p
48
+ end
49
+
50
+ class << self
51
+ # Makes sure n is in the range 0..1.
52
+ #
53
+ # @param n [Numeric] the value to truncate.
54
+ # @return [Float] n truncated to fit within the range 0..1.
55
+ def truncate(n)
56
+ if n <= 0 then 0.0
57
+ elsif n >= 1 then 1.0
58
+ else n
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # Vixel Buffer
6
+ #
7
+ # TODO: Document this class.
8
+ class VixelBuffer
9
+ include Buffer
10
+
11
+ # @return [Float] the global intensity of the buffer.
12
+ attr_accessor :intensity
13
+
14
+ # @return [Integer] the palette number currently in use.
15
+ attr_accessor :palette
16
+
17
+ # @!method vixels
18
+ # @return [Array<Vixel>] an array with the `Vixel` objects in the buffer.
19
+ alias vixels elements
20
+
21
+ # @param context [Context] the context in which the buffer exists.
22
+ # @param palette [Integer] the palette number to use when rendering.
23
+ # @param intensity [Numeric] the global intensity at which to render.
24
+ def initialize(context, palette: 0, intensity: 1.0)
25
+ super(context, Vixel)
26
+
27
+ @palette = palette
28
+ @intensity = intensity
29
+ end
30
+
31
+ # Render the layer vixels to the given buffer.
32
+ #
33
+ # @param buffer [PixelBuffer] the buffer to store the resulting colors of
34
+ # each point in.
35
+ # @param intensity [Numeric] the intensity to scale the vixels intensity
36
+ # with.
37
+ # @return [PixelBuffer] the same buffer that was given as a parameter.
38
+ def render(buffer, intensity: 1.0)
39
+ palette = context.palettes[@palette]
40
+ buffer.each_with_index do |color, index|
41
+ vixel = vixels[index]
42
+ next unless vixel.i.positive?
43
+
44
+ ratio = vixel.i * intensity * @intensity
45
+ color.mix_with! palette[vixel.p], ratio
46
+ end
47
+ buffer
48
+ end
49
+
50
+ # @return [Integer] the number of vixels in the buffer.
51
+ def vixel_count
52
+ vixels.length
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Vissen
6
+ module Output
7
+ # Stack
8
+ #
9
+ # TODO: Document this class.
10
+ class VixelStack
11
+ extend Forwardable
12
+
13
+ # @return [Array<VixelBuffer>] the layers that make up the stack.
14
+ attr_reader :layers
15
+
16
+ # @return [Context] the context in which the stack exist.
17
+ attr_reader :context
18
+
19
+ # @!method point_count
20
+ # @return [Integer] the number of points in each layer of the stack.
21
+ def_delegators :@context, :point_count
22
+
23
+ alias vixel_count point_count
24
+
25
+ # TODO: Make palettes a keyword argument in the next minor version.
26
+ #
27
+ # @raise [RangeError] if layer_count <= 0.
28
+ #
29
+ # @param context [Context] the context in which the stack exist.
30
+ # @param layer_count [Integer] the number of layers in the stack.
31
+ def initialize(context, layer_count)
32
+ raise RangeError if layer_count <= 0
33
+
34
+ @context = context
35
+ @layers = Array.new(layer_count) { VixelBuffer.new context }
36
+
37
+ freeze
38
+ end
39
+
40
+ # Prevents more layers and palettes from being added.
41
+ #
42
+ # @return [self]
43
+ def freeze
44
+ @layers.freeze
45
+ super
46
+ end
47
+
48
+ # Accesses a vixel in one of the vixelbuffers stored in the stack.
49
+ #
50
+ # @param layer [Integer] the index of the layer that is accessed.
51
+ # @param args (see VixelBuffer#[])
52
+ # @return [Vixel,nil] the vixel at the given layer.
53
+ def [](layer, *args)
54
+ @layers[layer][*args]
55
+ end
56
+
57
+ # @return [PixelBuffer] a new, uninitialized pixel buffer.
58
+ def pixel_buffer
59
+ PixelBuffer.new context
60
+ end
61
+
62
+ # Renders each layer and combines the result in the given buffer.
63
+ #
64
+ # TODO: Could we cache the result of this operation at time t to an
65
+ # internal PixelGrid and copy the stored information for subsequent
66
+ # requests at or around the same time?
67
+ #
68
+ # @raise [ContextError] if the pixel buffer does not share the same
69
+ # context.
70
+ #
71
+ # @param pixel_buffer [PixelBuffer] the buffer to store the resulting
72
+ # colors of each point in.
73
+ # @param intensity [Numeric] the intensity to scale the vixels intensity
74
+ # with.
75
+ # @return [PixelBuffer] the same buffer that was given as a parameter.
76
+ def render(pixel_buffer, intensity: 1.0)
77
+ raise ContextError unless context == pixel_buffer.context
78
+
79
+ pixel_buffer.clear!
80
+
81
+ @layers.reduce(pixel_buffer) do |a, e|
82
+ e.render a, intensity: intensity
83
+ end
84
+
85
+ pixel_buffer.finalize!
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vissen/output/version'
4
+
5
+ require 'vissen/output/error'
6
+ require 'vissen/output/context_error'
7
+ require 'vissen/output/color'
8
+ require 'vissen/output/filter'
9
+ require 'vissen/output/filter/quantizer'
10
+ require 'vissen/output/filter/gamma'
11
+ require 'vissen/output/pixel'
12
+ require 'vissen/output/point'
13
+ require 'vissen/output/vixel'
14
+ require 'vissen/output/palette'
15
+ require 'vissen/output/palettes'
16
+ require 'vissen/output/buffer'
17
+ require 'vissen/output/context'
18
+ require 'vissen/output/context/cloud'
19
+ require 'vissen/output/context/circle'
20
+ require 'vissen/output/context/grid'
21
+ require 'vissen/output/pixel_buffer'
22
+ require 'vissen/output/vixel_buffer'
23
+ require 'vissen/output/vixel_stack'
24
+
25
+ module Vissen
26
+ # The main job of the output module is to transform a multi layered collection
27
+ # of `Vixel` objects, a `VixelBuffer`, into a single layered collection of
28
+ # `Pixel`objects, a `PixelBuffer`.
29
+ module Output
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'vissen/output/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'vissen-output'
9
+ spec.version = Vissen::Output::VERSION
10
+ spec.authors = ['Sebastian Lindberg']
11
+ spec.email = ['seb.lindberg@gmail.com']
12
+
13
+ spec.summary = 'The output interface of the vissen system.'
14
+ spec.description = 'The output module implements all the objects and ' \
15
+ 'facilities used to talk to vissen sinks.'
16
+ spec.homepage = 'https://github.com/midi-visualizer/vissen-output'
17
+ spec.license = 'MIT'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
20
+ f.match(%r{^(test|spec|features)/})
21
+ end
22
+ spec.bindir = 'exe'
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.16'
27
+ spec.add_development_dependency 'minitest', '~> 5.0'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rubocop', '~> 0.52'
30
+ spec.add_development_dependency 'simplecov', '~> 0.16'
31
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vissen-output
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.1
5
+ platform: ruby
6
+ authors:
7
+ - Sebastian Lindberg
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.52'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.52'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.16'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.16'
83
+ description: The output module implements all the objects and facilities used to talk
84
+ to vissen sinks.
85
+ email:
86
+ - seb.lindberg@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rubocop.yml"
93
+ - ".travis.yml"
94
+ - CHANGELOG.md
95
+ - Gemfile
96
+ - Gemfile.lock
97
+ - LICENSE.txt
98
+ - README.md
99
+ - Rakefile
100
+ - bin/console
101
+ - bin/setup
102
+ - lib/vissen/output.rb
103
+ - lib/vissen/output/buffer.rb
104
+ - lib/vissen/output/color.rb
105
+ - lib/vissen/output/context.rb
106
+ - lib/vissen/output/context/circle.rb
107
+ - lib/vissen/output/context/cloud.rb
108
+ - lib/vissen/output/context/grid.rb
109
+ - lib/vissen/output/context_error.rb
110
+ - lib/vissen/output/error.rb
111
+ - lib/vissen/output/filter.rb
112
+ - lib/vissen/output/filter/gamma.rb
113
+ - lib/vissen/output/filter/quantizer.rb
114
+ - lib/vissen/output/palette.rb
115
+ - lib/vissen/output/palettes.rb
116
+ - lib/vissen/output/pixel.rb
117
+ - lib/vissen/output/pixel_buffer.rb
118
+ - lib/vissen/output/point.rb
119
+ - lib/vissen/output/version.rb
120
+ - lib/vissen/output/vixel.rb
121
+ - lib/vissen/output/vixel_buffer.rb
122
+ - lib/vissen/output/vixel_stack.rb
123
+ - vissen-output.gemspec
124
+ homepage: https://github.com/midi-visualizer/vissen-output
125
+ licenses:
126
+ - MIT
127
+ metadata: {}
128
+ post_install_message:
129
+ rdoc_options: []
130
+ require_paths:
131
+ - lib
132
+ required_ruby_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ required_rubygems_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ requirements: []
143
+ rubyforge_project:
144
+ rubygems_version: 2.7.3
145
+ signing_key:
146
+ specification_version: 4
147
+ summary: The output interface of the vissen system.
148
+ test_files: []