Glimmer Metronome & 안녕하세요, 캔버스 애니메이션 데이터 귀속!

27006 단어 musicguidesktopruby
어제 쿠션 연습을 할 때, 나는 나의 아이폰metronome 응용 프로그램이 최신 업데이트 후에 고장난 것을 발견했다. 왜냐하면 그것은 첫 번째 박자가 아니라 두 번째 박자에서 똑딱똑딱 소리가 나기 때문이다.이것은 작은 일이지만 상당히 짜증이 나서 나는 이 프로그램을 삭제했고 10분도 안 되는 시간에 최초의 4/4 리듬 버전을 위해 자신의 박자기 프로그램을 짰다Glimmer DSL for SWT.
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#metronome

require 'glimmer-dsl-swt'

class Metronome
  class Beat
    attr_accessor :on

    def off!
      self.on = false
    end

    def on!
      self.on = true
    end
  end

  class Rhythm
    attr_accessor :beats, :signature_top, :signature_bottom

    def initialize(signature_top, signature_bottom)
      @signature_top = signature_top
      @signature_bottom = signature_bottom
      @beats = @signature_top.times.map {Beat.new}
    end
  end

  include Glimmer::UI::CustomShell

  attr_reader :beats

  before_body {
    @rhythm = Rhythm.new(4, 4)
    @beats = @rhythm.beats
  }

  body {
    shell {
      grid_layout 4, true
      text 'Glimmer Metronome'
      minimum_size 200, 200

      4.times { |n|
        canvas {
          layout_data {
            width_hint 50
            height_hint 50
          }
          oval(0, 0, 50, 50) {
            background bind(self, "beats[#{n}].on") {|on| on ? :red : :yellow}
          }
        }
      }

      on_swt_show {
        @thread ||= Thread.new {
          4.times.cycle { |n|
            sleep(0.25)
            beats.each(&:off!)
            beats[n].on!
          }
        }
      }

      on_widget_disposed {
        @thread.kill # safe since no stored data is involved
      }
    }
  }
end

Metronome.launch

나중에 나는 더 많은 리듬/bpm 변체를 추가하고 이 프로그램을 Glimmer DSL for SWT'Elaborate Sample로 포함하기로 결정했다.사실상 이것은 첫 번째Glimmer DSL for SWT가 JRuby를 통해 크로스플랫폼Java Sound API에서 사용한 내부 예시를 보여준 것이다. 이것은 매우 실용적이고 유용한 특성이다(비록 미약한'외부 예시'가 사용했지만Java Sound APITimer).
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#metronome

require 'glimmer-dsl-swt'

class Metronome
  class Beat
    attr_accessor :on

    def off!
      self.on = false
    end

    def on!
      self.on = true
    end
  end

  class Rhythm
    attr_reader :beat_count
    attr_accessor :beats, :bpm

    def initialize(beat_count)
      self.beat_count = beat_count
      @bpm = 120
    end

    def beat_count=(value)
      @beat_count = value
      reset_beats!
    end

    def reset_beats!
      @beats = beat_count.times.map {Beat.new}
      @beats.first.on!
    end
  end

  include Glimmer::UI::CustomShell

  import 'javax.sound.sampled'

  GEM_ROOT = File.expand_path(File.join('..', '..'), __dir__)
  FILE_SOUND_METRONOME_UP = File.join(GEM_ROOT, 'sounds', 'metronome-up.wav')
  FILE_SOUND_METRONOME_DOWN = File.join(GEM_ROOT, 'sounds', 'metronome-down.wav')

  attr_accessor :rhythm

  before_body {
    @rhythm = Rhythm.new(4)
  }

  body {
    shell {
      row_layout(:vertical) {
        center true
      }
      text 'Glimmer Metronome'

      label {
        text 'Beat Count'
        font height: 30, style: :bold
      }

      spinner {
        minimum 1
        maximum 64
        selection bind(self, 'rhythm.beat_count', after_write: ->(v) {restart_metronome})
        font height: 30
      }

      label {
        text 'BPM'
        font height: 30, style: :bold
      }

      spinner {
        minimum 30
        maximum 1000
        selection bind(self, 'rhythm.bpm')
        font height: 30
      }

      @beat_container = beat_container

      on_swt_show {
        start_metronome
      }

      on_widget_disposed {
        stop_metronome
      }
    }
  }

  def beat_container
    composite {
      grid_layout(@rhythm.beat_count, true) {
        margin_left 10
      }

      @rhythm.beat_count.times { |n|
        canvas {
          rectangle(0, 0, 50, 50, 36, 36) {
            background bind(self, "rhythm.beats[#{n}].on") {|on| on ? :red : :yellow}
          }
        }
      }
    }
  end

  def start_metronome
    @thread ||= Thread.new {
      @rhythm.beat_count.times.cycle { |n|
        sleep(60.0/@rhythm.bpm.to_f)
        @rhythm.beats.each(&:off!)
        @rhythm.beats[n].on!
        sound_file = n == 0 ? FILE_SOUND_METRONOME_UP : FILE_SOUND_METRONOME_DOWN
        play_sound(sound_file)
      }
    }
    if @beat_container.nil?
      body_root.content {
        @beat_container = beat_container
      }
      body_root.layout(true, true)
      body_root.pack(true)
    end
  end

  def stop_metronome
    @thread&.kill # safe since no stored data is involved
    @thread = nil
    @beat_container&.dispose
    @beat_container = nil
  end

  def restart_metronome
    stop_metronome
    start_metronome
  end

  # Play sound with the Java Sound library
  def play_sound(sound_file)
    begin
      file_or_stream = java.io.File.new(sound_file)
      audio_stream = AudioSystem.get_audio_input_stream(file_or_stream)
      clip = AudioSystem.clip
      clip.open(audio_stream)
      clip.start
    rescue => e
      puts e.full_message
    end
  end
end

Metronome.launch

이것은 소리가 나는 Glimmer Metronome 프로그램의 동영상입니다. (나는 화살표와 페이지를 넘기고 페이지를 넘기는 키보드 단추로 마이크로모뎀을 늘려서 매번 10씩 증가/감소합니다.)
https://github.com/AndyObtiva/glimmer-dsl-swt/raw/master/videos/glimmer-metronome.mp4
코드는 주로 단독Thread 순환에 의존한다. 이 순환은 bpm과 박자 계수가 얼마나 되는지 검사하고 자바 사운드 API로 재생되는 박자기를 사용하여 위아래 소리wav 파일에서 소리를 선택한다.Thread 은식sync_exec 호출을 사용하여 GUI의 변경을 일으켜 같은 goby SWT에서 두 개의 박자가 바뀐 on과off 조명을 반복적으로 렌더링합니다. (단독 렌더링 이벤트로 렌더링하지 않기 때문에 가벼운 지연을 피할 수 있습니다. 이것은 도저히 느끼지 못할 수도 있지만 만약에sync exec를 사용합니다.)박자의 구조에 대해 나는 혼합 복합 레이아웃/화포 방법을 사용하여 Canvas Shape DSL을 여전히 이용하는 상황에서 화면의 각 박자의 위치를 계산하는 것을 피했다.내가 확보하고 싶은 마지막 일은 내가 박자(박자)를 줄이거나 늘리면 모든 박자가 수평선을 유지하기 위해 창의 크기를 조절할 것이다.이것은 app body root( shell 가 창을 대표하는widget)layoutpack 방법에 의존하여 이루어진 것으로 매개 변수가true이면 창의 레이아웃과 압축 크기를 완전히 새로 고칩니다.
이 매우 빠른 박자기 버전에서 나는 어떤 미친 듯이 완벽한 실시간 보증도 하지 않았다.비록 격자 레이아웃이 아니라 수학을 대량으로 사용할 수 있지만, 그것은 나의 요구를 충족시킬 수 있다.그럼에도 불구하고 Metronome 응용 프로그램은 전통적으로 몇 개월의 시간이 필요하다고 믿습니다.만약 네가 나처럼 하루도 안 되는 시간에 그것을 완성한다면, 너는 이렇게 많은 추가 시간을 써서 무엇을 할 수 있을지 상상해 봐라. animation 의 생산 효율 때문에 당신은 얼마나 많은 기능을 추가할 수 있습니까? 당신은 얼마나 많은 고객 프로젝트를 처리할 수 있습니까? 만약 당신이 이렇게 빨리 응용 프로그램을 납품한다면 당신은 추가 시간이나 남은 몇 달 동안 무엇을 할 수 있습니까?
data-binding based animation는 가장 효율적인 크로스플랫폼 데스크톱 개발 프레임워크입니다. none을 제외하고!프로그래밍 언어든 기술 창고든 글림머보다 더 효율적인 것이 무엇인지 모르겠다.모든 다른 해결 방안은 너무 번거롭고 강제적(Glimmer가 SWT를 겨냥한 영역의 특정 언어와 상반되거나), 관료주의와 의식화canvas의 스마트 기본 설정과 설정 관례와 상반되거나), XML/HTML 등 곤혹스럽거나 효율이 낮은 범례Glimmer DSL for SWT의 단일 언어 방법과 상반되거나,또는 정적 유형의 프로그래밍 언어를 바탕으로 GUI에 대한 효율이 높지 않다(동적 유형의 Ruby와 반대로 후자는 동적 GUI 창작에 적합하다)
그렇지 않으면 애니메이션'every'속성의 데이터 연결을 보여주는 또 다른 예시를 추가했습니다. 이름Glimmer DSL for SWT
# From: https://github.com/AndyObtiva/glimmer-dsl-swt/blob/master/docs/reference/GLIMMER_SAMPLES.md#hello-canvas-animation-data-binding

require 'glimmer-dsl-swt'
require 'bigdecimal'

class HelloAnimationDataBinding
  include Glimmer::UI::CustomShell

  attr_accessor :delay_time

  before_body {
    @delay_time = 0.050
  }

  body {
    shell {
      text 'Hello, Canvas Animation Data Binding!'
      minimum_size 320, 320

      canvas {
        grid_layout

        spinner {
          layout_data(:center, :center, true, true) {
            minimum_width 75
          }
          digits 3
          minimum 1
          maximum 100
          selection bind(self, :delay_time, on_read: ->(v) {(BigDecimal(v.to_s)*1000).to_f}, on_write: ->(v) {(BigDecimal(v.to_s)/1000).to_f})
        }
        animation {
          every bind(self, :delay_time)

          frame { |index|
            background rgb(index%100, index%100 + 100, index%55 + 200)
            oval(index*3%300, index*3%300, 20, 20) {
              background :yellow
            }
          }
        }
      }
    }
  }
end

HelloAnimationDataBinding.launch
다음은 그의 애니메이션 캡처입니다.
Glimmer DSL for SWT
즐거움Glimmer DSL for SWT!
p. 나의 상박자와 하박자의 반전이나 잘못된 사용에 충격을 받은 철봉 음악 애호가들에 대한 설명을 기억해야 한다.우선, 나는 멜로디 음악가가 아니라 드럼리스트이다.따라서 고수들은 리듬 계수 중의 매 박자를 모두 하박자(즉 1, 2, 3, 4)라고 부른다.이어서 나는 펑크 록 가수로 모두가 내가 펑크 드럼을 칠 줄 안다.이게 무슨 소리야!?펑크 드럼리스트는 음악 규칙을 전혀 존중하지 않는다.사실 그들은 매일 자신의 규칙을 쓰고 음악의 규칙을 완전히 어긴다.그래서 나는 첫 번째 박자를'낙관적'이라고 부르는 생각을 했다. 왜냐하면 박자가 첫 번째 박자에서 날카로운 고음을 내기 때문이다.이해해 주셔서 감사합니다. 멋진 펑크 록의 날을 보내세요!

좋은 웹페이지 즐겨찾기