vissen-output 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []