vissen-output 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: ee97aa25edd367c68a4f113fac72270890711d5859eb61bec40a71470753fb8e
4
+ data.tar.gz: c1069056b86a4f7d62ab4e5d5602bcf5c8131d684e8dc9631955f2582d516e3a
5
+ SHA512:
6
+ metadata.gz: 7475b3b4f78d4fd8f0a656d9dc3e45ade1af5a06e1596df9faa5de8eaa508c3489001b714aaf8f509f9b09d9416ecd99c95ac8682aa17f4cc5ced85003299ad1
7
+ data.tar.gz: 9c552a4b52af3646f6459116e3dda5a297c147886f90c261bb85448b1c978eda53155f68028d186af7b7fa0a77c428e4c9e598ae2ae2ebfb67069e46f2ba54ab
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,64 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'vendor/**/*'
4
+ - 'tmp/**/*'
5
+ TargetRubyVersion: 2.5
6
+
7
+ Style/FrozenStringLiteralComment:
8
+ EnforcedStyle: always
9
+
10
+ Layout/EndOfLine:
11
+ EnforcedStyle: lf
12
+
13
+ Layout/ClassStructure:
14
+ Enabled: true
15
+ Categories:
16
+ module_inclusion:
17
+ - include
18
+ - prepend
19
+ - extend
20
+ ExpectedOrder:
21
+ - module_inclusion
22
+ - constants
23
+ - public_class_methods
24
+ - initializer
25
+ - instance_methods
26
+ - protected_methods
27
+ - private_methods
28
+
29
+ Layout/IndentHeredoc:
30
+ EnforcedStyle: squiggly
31
+
32
+ Lint/AmbiguousBlockAssociation:
33
+ Exclude:
34
+ - 'test/**/*.rb'
35
+
36
+ Lint/InterpolationCheck:
37
+ Exclude:
38
+ - 'test/**/*.rb'
39
+
40
+ Metrics/BlockLength:
41
+ Exclude:
42
+ - 'Rakefile'
43
+ - '**/*.rake'
44
+ - 'test/**/*.rb'
45
+
46
+ Metrics/ModuleLength:
47
+ Exclude:
48
+ - 'test/**/*.rb'
49
+
50
+ Metrics/ParameterLists:
51
+ CountKeywordArgs: false
52
+
53
+ Naming/UncommunicativeMethodParamName:
54
+ AllowedNames:
55
+ - x
56
+ - y
57
+ - i
58
+ - p
59
+ - n
60
+ - r
61
+ - g
62
+ - b
63
+ - to
64
+
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ before_install: gem install bundler -v 1.16.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,61 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
+ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+ ## [0.6.1] - 2018-04-20
9
+ ### Changed
10
+ - Improved, more descriptive comments.
11
+
12
+ ## [0.6.0] - 2018-04-14
13
+ ### Added
14
+ - Output filter support in PixelBuffer.
15
+ - More descriptive ContextErrors that are raised when contexts do not match.
16
+
17
+ ### Changed
18
+ - Grid context now accepts a with and height instead of an aspect ratio.
19
+
20
+ ## [0.5.1] - 2018-04-14
21
+ ### Added
22
+ - PixelBuffer#finalize!.
23
+ - The convenience method Context::Cloud.scatter that randomly places n points.
24
+
25
+ ### Fixed
26
+ - A bug in the Circle context caused the circle to be centered in (0,0), rather than in the center of the context.
27
+
28
+ ## [0.5.0] - 2018-04-13
29
+ ### Changed
30
+ - Changed the name of the Cloud module to Buffer to distance it from the cloud context.
31
+ - Moved all context to their own submodule.
32
+ - Changed the name of the PixelCloud to PixelBuffer to better indicate what it should be used for.
33
+ - Changed the name of the VixelCloud to VixelBuffer to better indicate what it should be used for.
34
+
35
+ ### Removed
36
+ - The Grid class.
37
+
38
+ ## [0.4.1] - 2018-04-13
39
+ ### Added
40
+ - A Circle context.
41
+
42
+ ### Changed
43
+ - Improved the documentation.
44
+
45
+ ## [0.4.0] - 2018-04-10
46
+ ### Added
47
+ - Output filters.
48
+ - Gamma filter.
49
+ - Quantizer filter.
50
+ - Introduced the more general concept of point clouds.
51
+ - Created the Context as a more general form of the GridContext.
52
+ - Create a new CloudContext that handles arbitrarily positioned Point objects.
53
+
54
+ ### Changed
55
+ - Made the Grid into a special kind of Cloud.
56
+ - Made the VixelGrid into a VixelCloud.
57
+ - Made the PixelGrid into a PixelCloud.
58
+ - The GridContext is now a class instead of a module.
59
+ - The Stack is now longer a GridContext but instead accepts one as its first argument.
60
+ - The argument order of Vixel.new is now reversed, so that is is alphabetical.
61
+ - Renamed Stack -> VixelStack.
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in vissen-output.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,46 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ vissen-output (0.6.1)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ docile (1.3.0)
11
+ json (2.1.0)
12
+ minitest (5.11.3)
13
+ parallel (1.12.1)
14
+ parser (2.5.1.0)
15
+ ast (~> 2.4.0)
16
+ powerpack (0.1.1)
17
+ rainbow (3.0.0)
18
+ rake (10.5.0)
19
+ rubocop (0.55.0)
20
+ parallel (~> 1.10)
21
+ parser (>= 2.5)
22
+ powerpack (~> 0.1)
23
+ rainbow (>= 2.2.2, < 4.0)
24
+ ruby-progressbar (~> 1.7)
25
+ unicode-display_width (~> 1.0, >= 1.0.1)
26
+ ruby-progressbar (1.9.0)
27
+ simplecov (0.16.1)
28
+ docile (~> 1.1)
29
+ json (>= 1.8, < 3)
30
+ simplecov-html (~> 0.10.0)
31
+ simplecov-html (0.10.2)
32
+ unicode-display_width (1.3.0)
33
+
34
+ PLATFORMS
35
+ ruby
36
+
37
+ DEPENDENCIES
38
+ bundler (~> 1.16)
39
+ minitest (~> 5.0)
40
+ rake (~> 10.0)
41
+ rubocop (~> 0.52)
42
+ simplecov (~> 0.16)
43
+ vissen-output!
44
+
45
+ BUNDLED WITH
46
+ 1.16.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Sebastian Lindberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Vissen::Output
2
+
3
+ [![Build Status](https://travis-ci.org/midi-visualizer/vissen-output.svg?branch=master)](https://travis-ci.org/midi-visualizer/vissen-output)
4
+ [![Inline docs](http://inch-ci.org/github/midi-visualizer/vissen-output.svg?branch=master)](http://inch-ci.org/github/midi-visualizer/vissen-output)
5
+
6
+ The Vissen Output library implements the objects used by the Vissen Engine to talk to the various sinks.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'vissen-output'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install vissen-output
23
+
24
+ ## Usage
25
+
26
+ TODO: Write usage instructions here
27
+
28
+ ## Development
29
+
30
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
31
+
32
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
33
+
34
+ ## Contributing
35
+
36
+ Bug reports and pull requests are welcome on GitHub at https://github.com/midi-visualizer/vissen-output.
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'rubocop/rake_task'
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'test'
9
+ t.libs << 'lib'
10
+ t.test_files = FileList['test/**/*_test.rb']
11
+ end
12
+
13
+ RuboCop::RakeTask.new(:rubocop) do |t|
14
+ t.options = ['-a']
15
+ end
16
+
17
+ task default: :test
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'vissen/output'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require 'pry'
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'forwardable'
4
+
5
+ module Vissen
6
+ module Output
7
+ # Buffer
8
+ #
9
+ #
10
+ module Buffer
11
+ extend Forwardable
12
+
13
+ # @return [Context] the context of the buffer.
14
+ attr_reader :context
15
+
16
+ # @return [Object] the elements at the buffer points.
17
+ attr_reader :elements
18
+
19
+ def_delegators :@context, :width, :height
20
+ def_delegators :@elements, :each, :each_with_index
21
+
22
+ # The grid is setup with a grid context as well as a class to places
23
+ # instances of in every grid point.
24
+ #
25
+ # @raise [ArgumentError] if both an element class and a block are given.
26
+ #
27
+ # @param context [Context] the context in which the buffer exists.
28
+ # @param elements_klass [Class] the class to use when allocating
29
+ # elements.
30
+ # @param block [Proc] the block to use instead of `elements_klass` when
31
+ # allocating element objects.
32
+ def initialize(context, elements_klass = nil, &block)
33
+ @context = context
34
+ @elements =
35
+ if block_given?
36
+ raise ArgumentError if elements_klass
37
+ context.alloc_points(&block).freeze
38
+ else
39
+ context.alloc_points(elements_klass).freeze
40
+ end
41
+ end
42
+
43
+ # Prevents the context and element array from being changed.
44
+ #
45
+ # @return [self]
46
+ def freeze
47
+ @elements.freeze
48
+ super
49
+ end
50
+
51
+ # Context specific element accessor. Depends on `Context#index_from` to
52
+ # transform `args` into an index.
53
+ #
54
+ # @param args (see Context#index_from).
55
+ # @return [Object] the element at the given index.
56
+ def [](*args)
57
+ @elements[@context.index_from(*args)]
58
+ end
59
+
60
+ # Iterates over each element in the buffer and yields the element along
61
+ # with its x and y coordinates.
62
+ #
63
+ # @return (see Context#each_position).
64
+ def each_with_position
65
+ return to_enum(__callee__) unless block_given?
66
+ @context.each_position { |i, x, y| yield @elements[i], x, y }
67
+ end
68
+
69
+ # Two buffers are considered equal if they share the same context.
70
+ #
71
+ # @param other [#context, Object]
72
+ # @return [true, false] true if the other object share the same context.
73
+ def share_context?(other)
74
+ @context == other.context
75
+ rescue NoMethodError
76
+ false
77
+ end
78
+
79
+ alias === share_context?
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ # Basic value object representing a color in the RGB color space.
6
+ #
7
+ # == Usage
8
+ # The following example creates two colors, mixes them, and converts the
9
+ # result to an array of color component.
10
+ #
11
+ # color_a = Color.new 0.3, 0.6, 0.2
12
+ # color_b = Color.new 0.1, 0.2, 0.5
13
+ #
14
+ # color_a.mix_with(color_b, 0.5).to_a => [0.2, 0.3, 0.35]
15
+ #
16
+ class Color
17
+ # Accessors for the red, green and blue color components.
18
+ attr_accessor :r, :g, :b
19
+
20
+ # @param r [Float] the red color value in the range (0..1).
21
+ # @param g [Float] the green color value in the range (0..1).
22
+ # @param b [Float] the blue color value in the range (0..1).
23
+ def initialize(r = 0.0, g = 0.0, b = 0.0)
24
+ @r = r
25
+ @g = g
26
+ @b = b
27
+ end
28
+
29
+ # Color equality based on component values.
30
+ #
31
+ # TODO: Add some small delta around what is considered the same color?
32
+ # Perhaps scale to 255 and floor before comparing?
33
+ #
34
+ # @param other [Object] the object to check equality against.
35
+ # @return [true, false] true when two colors are exactly the same.
36
+ def ==(other)
37
+ r == other.r && g == other.g && b == other.b
38
+ rescue NoMethodError
39
+ false
40
+ end
41
+
42
+ # Creates a new array from the color.
43
+ #
44
+ # @return [Array<Float>] a new array containing the red, green and blue
45
+ # color values.
46
+ def to_a
47
+ [r, g, b]
48
+ end
49
+
50
+ # rubocop:disable Metrics/AbcSize
51
+
52
+ # Moves this color toword the other based on the given ratio.
53
+ #
54
+ # ratio = 0 -> 100 % of this color
55
+ # ratio = 1 -> 100 % of the other color
56
+ #
57
+ # @param other [Color] the color to mix with
58
+ # @param ratio [Float] the amount (0..1) of the other color to mix in.
59
+ # @return [self]
60
+ def mix_with!(other, ratio)
61
+ anti_ratio = (1 - ratio)
62
+
63
+ self.r = r * anti_ratio + other.r * ratio
64
+ self.g = g * anti_ratio + other.g * ratio
65
+ self.b = b * anti_ratio + other.b * ratio
66
+
67
+ self
68
+ end
69
+ # rubocop:enable Metrics/AbcSize
70
+
71
+ # Returns a new color that is a mix between this and the other color,
72
+ # based on the ratio. See `#mix_with!` for more details.
73
+ #
74
+ # @param (see #mix_with!)
75
+ # @return [Color] the result of the mix.
76
+ def mix_with(other, ratio)
77
+ dup.mix_with! other, ratio
78
+ end
79
+
80
+ # Returns a string formatted in the tradiotioal hex representation of a
81
+ # color: #04A4BF.
82
+ #
83
+ # @return [String] the object string representation.
84
+ def inspect
85
+ format('#%02X%02X%02X', *to_a.map! { |v| (v * 255).round })
86
+ end
87
+
88
+ class << self
89
+ # Cast a given object to a color.
90
+ #
91
+ # @param obj [Color, Array<Numeric>, Integer, #to_a] the object to
92
+ # coerce.
93
+ # @return [Color] a new color object.
94
+ def from(obj)
95
+ case obj
96
+ when self then obj
97
+ when Array then new(*obj)
98
+ when Integer then from_integer obj
99
+ else
100
+ new(*obj.to_a)
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def from_integer(int)
107
+ b = (int & 0xFF) / 255.0
108
+ int >>= 8
109
+ g = (int & 0xFF) / 255.0
110
+ int >>= 8
111
+ r = (int & 0xFF) / 255.0
112
+
113
+ new r, g, b
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vissen
4
+ module Output
5
+ module Context
6
+ # Output context with the points placed counter clockwise on a circle. By
7
+ # specifying an offset it is possible to adjust the position of the end
8
+ # points of the element array.
9
+ class Circle < Cloud
10
+ # @param point_count [Integer] the number of points.
11
+ # @param offset [Numeric] the angle offset, in radians, of the first
12
+ # point.
13
+ # @param width [Numeric] (see Context)
14
+ # @param height [Numeric] (see Context)
15
+ # @param radius [Numeric] the radius of the context.
16
+ # @param args (see CloudContext).
17
+ def initialize(point_count,
18
+ offset: 0,
19
+ width: 1.0,
20
+ height: 1.0,
21
+ radius: [width, height].min / 2.0,
22
+ **args)
23
+
24
+ circle = self.class.position_generator(point_count, radius, offset)
25
+ center = [width.to_f / 2, height.to_f / 2]
26
+ points = self.class.place_points circle, center
27
+
28
+ super(points, width: width, height: height, **args)
29
+ end
30
+
31
+ class << self
32
+ # Creates a generator (`Enumerator`) for x and y coordinates
33
+ # equidistantly placed along a circle centered around (0, 0).
34
+ #
35
+ # @param point_count [Integer] the number of points along the circle.
36
+ # @param radius [Numeric] the radius of the circle.
37
+ # @param offset [Numeric] the angular offset of the first point. An
38
+ # offset of pi/2 would place the first point at the twelve o'clock
39
+ # position.
40
+ # @return [Enumerator] an enumerator that yields `point_count` x and y
41
+ # coordinates along a circle.
42
+ def position_generator(point_count, radius, offset = 0)
43
+ angle_factor = 2.0 * Math::PI / point_count
44
+
45
+ Enumerator.new(point_count) do |y|
46
+ point_count.times do |index|
47
+ angle = index * angle_factor + offset
48
+ y << [radius * Math.cos(angle), radius * Math.sin(angle)]
49
+ end
50
+ end
51
+ end
52
+
53
+ # Uses a position generator to allocate an array of `Point` objects
54
+ # placed arount a circle centered around the given coordinates.
55
+ #
56
+ # @param generator [Enumerator] the position generator
57
+ # (see .position_generator).
58
+ # @param center [Array<Numeric>] the x and y coordinates of the
59
+ # circle center.
60
+ # @return [Array<Point>] an array of `Point` objects placed around a
61
+ # circle.
62
+ def place_points(generator, center)
63
+ x0, y0 = center
64
+ generator.map { |x, y| Point.new x0 + x, y0 + y }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end