fun Java MIDI API things
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

148 lines
4.2 KiB

  1. package me.jfenn.exampleaudio
  2. import kotlinx.coroutines.runBlocking
  3. import me.jfenn.audio.AudioManager
  4. import me.jfenn.audio.constants.*
  5. import me.jfenn.audio.impl.MidiInstrument
  6. import me.jfenn.audio.model.Note
  7. import me.jfenn.audio.model.applyAll
  8. import me.jfenn.audio.model.toNote
  9. import me.jfenn.audio.shared
  10. import me.jfenn.audio.playOn
  11. import me.jfenn.audio.then
  12. import me.jfenn.audio.utils.extensions.random
  13. import me.jfenn.audio.utils.extensions.spread
  14. import me.jfenn.audio.utils.extensions.toMidi
  15. import me.jfenn.audio.utils.metronome
  16. import me.jfenn.audio.utils.notes.ScaleType
  17. import javax.swing.JButton
  18. import javax.swing.JFrame
  19. object RandomPitchStrings {
  20. val scale = ScaleType.MAJOR.fromNote("2C".toMidi(), take = 24)
  21. val strings = MidiInstrument(0, STRING_ENSEMBLE_2)
  22. val harpsichord = MidiInstrument(1, HARPSICHORD)
  23. val guitar = MidiInstrument(2, ACOUSTIC_GUITAR_NYLON)
  24. val musicbox = MidiInstrument(3, MUSIC_BOX)
  25. val hihat = MidiInstrument(4, SFX_GUNSHOT)
  26. val woodblock = MidiInstrument(6, WOODBLOCK)
  27. fun playMain(audio: AudioManager) = audio.metronome(4000).also { metro ->
  28. val pitch = metro.onTick
  29. .random(0, 1, 2, 4, 5, isUnique = true)
  30. .shared()
  31. // strings
  32. pitch.transform { i ->
  33. emit(scale[i])
  34. emit(scale[0] + 12)
  35. emit(scale[6] + 12)
  36. emit(scale[i] + 24)
  37. }.toNote {
  38. duration = 3000
  39. velocity = 70
  40. }.playOn(strings)
  41. // chord
  42. pitch.transform { i ->
  43. emit(Note(scale[i] + 12, 250), 150)
  44. emit(Note(scale[i] + 24, 250), 200)
  45. emit(Note(scale[i] + 36, 250), 250)
  46. }.applyAll {
  47. velocity = 60
  48. }.playOn(harpsichord)
  49. // melody
  50. pitch.transform { i ->
  51. if (Math.random() < 0.7) {
  52. emit(Note(scale[i], 250), 1000)
  53. emit(Note(scale[0] + 12, 250), 2000)
  54. emit(Note(scale[6], 250), 3000)
  55. }
  56. }.playOn(guitar)
  57. var isPercussion = false
  58. metro.onTick.then {
  59. isPercussion = Math.random() < 0.5
  60. }
  61. // bass
  62. metro.onTick.transform {
  63. emit(Note(28, 1500, 100))
  64. emit(Note(28, 1500, 100), 2000)
  65. }.playOn(musicbox)
  66. // tempo beat / percussion
  67. metro.onTick.transform {
  68. if (isPercussion) {
  69. emit(Note(44, 100), 500)
  70. emit(Note(44, 100), 1500)
  71. emit(Note(44, 100), 2500)
  72. emit(Note(44, 100), 3500)
  73. }
  74. }.playOn(hihat)
  75. // woodblock
  76. metro.onTick.transform {
  77. if (isPercussion) for (i in (0..7)) {
  78. emit(Note(70, 100, 60), i * 500L)
  79. emit(Note(70, 100, 60), 250 + (i * 500L))
  80. }
  81. }.playOn(woodblock)
  82. }
  83. fun playEnding(audio: AudioManager) = audio.metronome(4000).also { metro ->
  84. val ending = metro.onTick.take(1).shared()
  85. ending.transform {
  86. emit(scale[0] + 12)
  87. emit(scale[2] + 12)
  88. emit(scale[6] + 12)
  89. emit(scale[6] + 24)
  90. }.toNote {
  91. duration = 4000
  92. velocity = 70
  93. }.playOn(strings)
  94. ending.transform {
  95. emit(Note(scale[4], 250))
  96. }.playOn(guitar)
  97. ending.transform {
  98. emit(scale[1] + 12)
  99. emit(scale[2] + 12)
  100. emit(scale[4] + 12)
  101. emit(scale[6] + 12)
  102. emit(scale[7] + 12)
  103. }.toNote {
  104. duration = 250
  105. }.spread(500).transform { note ->
  106. emit(note)
  107. emit(note.copy(number = note.number + 12), 50)
  108. }.playOn(harpsichord)
  109. ending.transform {
  110. emit(Note(28, 1500, 100))
  111. }.playOn(musicbox)
  112. }
  113. @JvmStatic
  114. fun main(args: Array<String>) = runBlocking {
  115. val audio = AudioManager(scope = this)
  116. val main = playMain(audio)
  117. // interface
  118. val frame = JFrame()
  119. frame.add(JButton("Stop").apply {
  120. addActionListener {
  121. main.stop()
  122. playEnding(audio)
  123. }
  124. })
  125. frame.isVisible = true
  126. }
  127. }