picotune 0.0.4 → 0.0.8

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.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/picotune.rb +66 -31
  3. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a35c7146e96a70bdf13083331db163fda9137e6cd10baac06e0fd6ef517de77e
4
- data.tar.gz: acd8d878432d7770e168aa0307b5d3496c502f22593ad2df5e2dcac651d91b94
3
+ metadata.gz: de0cea1678fa0056bb4da4e3a016166160b1e1190a13f067f38d6cf620d07a54
4
+ data.tar.gz: f18fb53c744d050f6cf6632855fbd239fb4cd3ce45fa636f18dc27d65f42355c
5
5
  SHA512:
6
- metadata.gz: 7607d472022133602b24139e9508d9bd68b4066994f445386faf2dac2272e132d5df6601423dbb0f292c10170f75f72650ed4ba38711c63d83e11e246c182efe
7
- data.tar.gz: 4e5dbb38360c7f2db24cc0f7801a8973b79d4448cc72565913b4fd52d147514973c4ea3a2f1781602373d8d51d2e3b8d22211243b3996d2c3fa944c2a1e51657
6
+ metadata.gz: e745f4dd1af6767c828f711019a8c3a2c9f16027b5a7dba7647c519e2dfe06fa24ec8a00c51219b599092854f1a1e7b5918801846684d2b4ded7b1403fd50771
7
+ data.tar.gz: d532fac56aac02ad6353c3328ed2baca6a968566bbe721dbec25e7969ccb5e7f73b7b60b4869ddfa49a5e27eb17e7cc6dc5acd2fc90d186c1b7f94308a9ad189
data/lib/picotune.rb CHANGED
@@ -49,17 +49,18 @@ class PicoTune::Sample
49
49
  @left += sample.left
50
50
  @right += sample.right
51
51
 
52
- # "foldback" instead of hard clipping, sounds cool
52
+ # hard clip
53
+
53
54
  if @left > 1.0
54
- @left = 1.0 - (@left - 1.0) # ex: 1.0 - (1.2 - 1.0) => 1.0 - 0.2 => 0.8
55
+ @left = 1.0
55
56
  elsif @left < -1.0
56
- @left = -1.0 - (@left + 1.0) # ex: -1.0 - (-1.2 + 1.0) => -1.0 - -0.2 => -0.8
57
+ @left = -1.0
57
58
  end
58
59
 
59
60
  if @right > 1.0
60
- @right = 1.0 - (@right - 1.0)
61
+ @right = 1.0
61
62
  elsif @right < -1.0
62
- @right = -1.0 - (@right + 1.0)
63
+ @right = -1.0
63
64
  end
64
65
 
65
66
  self # return self to chain ops EX: sample.add(sample).add(sample) etc
@@ -75,10 +76,9 @@ class PicoTune::Sample
75
76
  end
76
77
 
77
78
  class PicoTune::WaveSample
78
- def initialize tone, samples_per_wave, multiplier = nil
79
+ def initialize tone, samples_per_wave
79
80
  @tone = tone
80
81
  @samples_per_wave = samples_per_wave
81
- @multiplier = multiplier
82
82
  end
83
83
 
84
84
  def sample index
@@ -101,43 +101,42 @@ class PicoTune::WaveSample
101
101
  end
102
102
 
103
103
  def sine index
104
- Math.sin(index / (@samples_per_wave / (Math::PI * 2))) * (@multiplier || 0.5)
104
+ Math.sin(index / (@samples_per_wave / (Math::PI * 2)))
105
105
  end
106
106
 
107
107
  def saw index
108
108
  interval = @samples_per_wave / 2
109
109
  half_interval = interval / 2
110
110
  percent = ((index + half_interval) % interval) / interval.to_f
111
- ((0.6 * percent) - 0.3) * (@multiplier || 0.5)
111
+ ((0.6 * percent) - 0.3)
112
112
  end
113
113
 
114
114
  def square index
115
- (index <= @samples_per_wave / 2 ? 1.0 : -1.0) * (@multiplier || 0.25)
115
+ (index <= @samples_per_wave / 2 ? 1.0 : -1.0)
116
116
  end
117
117
 
118
118
  def noise index
119
119
  value = sine index
120
120
  rand = Random.rand - 0.5
121
- value * rand * (@multiplier || 0.5)
121
+ value * rand
122
122
  end
123
123
 
124
124
  def triangle index
125
125
  half = @samples_per_wave / 2
126
126
  quarter = @samples_per_wave / 4
127
127
  ramp = 1.0 / quarter
128
- m = @multiplier || 0.5
129
128
 
130
129
  if index <= half
131
130
  if index <= quarter
132
- index * ramp * m
131
+ index * ramp
133
132
  else
134
- (half - index) * ramp * m
133
+ (half - index) * ramp
135
134
  end
136
135
  else
137
136
  if index <= half + quarter
138
- -((index - half) * ramp) * m
137
+ -((index - half) * ramp)
139
138
  else
140
- -((@samples_per_wave - index) * ramp) * m
139
+ -((@samples_per_wave - index) * ramp)
141
140
  end
142
141
  end
143
142
  end
@@ -150,6 +149,22 @@ class PicoTune::Tune
150
149
  @name = name
151
150
  @sequence = sequence
152
151
  @phrases = phrases
152
+
153
+ @phrases.each do |p|
154
+ p.tune = self
155
+ end
156
+ end
157
+
158
+ def volume_factor_for_simultaneous_melodies
159
+ max_melodies_in_phrases = 0
160
+
161
+ @phrases.each do |phrase|
162
+ if phrase.simultaneous_melodies > max_melodies_in_phrases
163
+ max_melodies_in_phrases = phrase.simultaneous_melodies
164
+ end
165
+ end
166
+
167
+ 1.0 / max_melodies_in_phrases if max_melodies_in_phrases > 0
153
168
  end
154
169
 
155
170
  def buffer
@@ -193,7 +208,8 @@ class PicoTune::Tune
193
208
  end
194
209
 
195
210
  class PicoTune::Phrase
196
- attr_reader :name, :tempo, :beats, :subbeats, :melodies
211
+ attr_reader :name, :tempo, :beats, :subbeats, :melodies, :simultaneous_melodies
212
+ attr_accessor :tune
197
213
 
198
214
  def initialize name, tempo, beats, subbeats, melodies
199
215
  @name = name
@@ -201,6 +217,11 @@ class PicoTune::Phrase
201
217
  @beats = beats.to_i
202
218
  @subbeats = subbeats.to_i
203
219
  @melodies = melodies
220
+ @simultaneous_melodies = @melodies.count
221
+
222
+ @melodies.each do |m|
223
+ m.instrument.phrase = self
224
+ end
204
225
  end
205
226
 
206
227
  def seconds_per_beat
@@ -221,7 +242,7 @@ class PicoTune::Phrase
221
242
 
222
243
  @melodies.each do |melody|
223
244
  temp = Array.new(buffer_size) { PicoTune::Sample.new } if melody.instrument.reverb?
224
- sub_buffer_size = (buffer_size.to_f / (@beats * @subbeats)).ceil
245
+ sub_buffer_size = buffer_size / (@beats * @subbeats)
225
246
  last_step_number = -1
226
247
  carry_over = 0
227
248
 
@@ -269,7 +290,7 @@ class PicoTune::Phrase
269
290
  temp[i + melody.instrument.reverb_offset] = verb_sample
270
291
  end
271
292
 
272
- samples[i] = samples[i].add temp[i]
293
+ samples[i] = (samples[i] || PicoTune::Sample.new).add temp[i]
273
294
 
274
295
  i += 1
275
296
  end
@@ -285,8 +306,9 @@ end
285
306
 
286
307
  class PicoTune::Instrument
287
308
  attr_reader :name, :tone, :length, :volume, :pan, :reverb
309
+ attr_accessor :phrase
288
310
 
289
- def initialize name, tone = 0, length = 'full', volume = 'full', pan = 'center', reverb = 'none'
311
+ def initialize name, tone, length, volume, pan, reverb
290
312
  @name = name
291
313
  @tone = tone
292
314
  @length = length
@@ -307,6 +329,8 @@ class PicoTune::Instrument
307
329
  0.75
308
330
  when 'full'
309
331
  1.0
332
+ else
333
+ 1.0
310
334
  end
311
335
  end
312
336
 
@@ -322,6 +346,8 @@ class PicoTune::Instrument
322
346
  0.75
323
347
  when 'full'
324
348
  1.0
349
+ else
350
+ 1.0
325
351
  end
326
352
  end
327
353
 
@@ -337,11 +363,13 @@ class PicoTune::Instrument
337
363
  3
338
364
  when 'right'
339
365
  4
366
+ else
367
+ 2
340
368
  end
341
369
  end
342
370
 
343
371
  def delay
344
- @reverb == 'none' ? 0.0 : 0.1
372
+ @reverb == 'none' ? 0.0 : 0.08
345
373
  end
346
374
 
347
375
  def decay
@@ -349,11 +377,11 @@ class PicoTune::Instrument
349
377
  when 'none'
350
378
  0.0
351
379
  when 'some'
352
- 0.25
380
+ 0.1
353
381
  when 'more'
354
- 0.5
382
+ 0.3
355
383
  when 'lots'
356
- 0.75
384
+ 0.5
357
385
  else
358
386
  0.0
359
387
  end
@@ -369,16 +397,23 @@ class PicoTune::Instrument
369
397
 
370
398
  def wave wave_index, note
371
399
  frequency = frequency_for_note note
372
- samples_per_wave = (PicoTune::SAMPLE_RATE / frequency).ceil
400
+ samples_per_wave = (PicoTune::SAMPLE_RATE / frequency).to_i
373
401
  sample = PicoTune::WaveSample.new(@tone, samples_per_wave).sample wave_index
374
402
  sample.modify_left :*, volume_value * (1 - pan_value / 4.0)
375
403
  sample.modify_right :*, volume_value * (pan_value / 4.0)
404
+
405
+ if v = phrase&.tune&.volume_factor_for_simultaneous_melodies
406
+ sample.modify_left :*, v
407
+ sample.modify_right :*, v
408
+ end
409
+
376
410
  sample
377
411
  end
378
412
 
379
413
  def samples_per_wave note
380
414
  frequency = frequency_for_note note
381
- (PicoTune::SAMPLE_RATE / frequency).ceil end
415
+ (PicoTune::SAMPLE_RATE / frequency).to_i
416
+ end
382
417
 
383
418
  def frequency_for_note note
384
419
  parts = note.split ''
@@ -434,11 +469,11 @@ class PicoTune::Assembler
434
469
  instruments = list.select { |item| item['type'] == 'instrument' }.map do |item|
435
470
  PicoTune::Instrument.new(
436
471
  item['name'],
437
- item['tone'],
438
- item['length'],
439
- item['volume'],
440
- item['pan'],
441
- item['reverb']
472
+ item['tone'] || 'sine',
473
+ item['length'] || 'full',
474
+ item['volume'] || 'full',
475
+ item['pan'] || 'center',
476
+ item['reverb'] || 'none'
442
477
  )
443
478
  end
444
479
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: picotune
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zachary Schroeder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-13 00:00:00.000000000 Z
11
+ date: 2021-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: wavefile
@@ -25,6 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.1.1
27
27
  description: Use a text file with a simple DSL to generate a musical (maybe) wav file.
28
+ See https://github.com/robobluebird/picotune for DSL documentation!
28
29
  email: schroza@gmail.com
29
30
  executables:
30
31
  - picotune
@@ -33,10 +34,13 @@ extra_rdoc_files: []
33
34
  files:
34
35
  - bin/picotune
35
36
  - lib/picotune.rb
36
- homepage: https://rubygems.org/gems/picotune
37
+ homepage: https://github.com/robobluebird/picotune
37
38
  licenses:
38
39
  - MIT
39
- metadata: {}
40
+ metadata:
41
+ documentation_uri: https://github.com/robobluebird/picotune
42
+ homepage_uri: https://github.com/robobluebird/picotune
43
+ source_code_uri: https://github.com/robobluebird/picotune
40
44
  post_install_message:
41
45
  rdoc_options: []
42
46
  require_paths: