feat: composer
This commit is contained in:
parent
314957eeb5
commit
bbef6cb342
@ -1,20 +1,75 @@
|
||||
package quaedam.projection.music
|
||||
|
||||
import kotlin.math.abs
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
object Composer {
|
||||
/**
|
||||
* The composer for music.
|
||||
* rhythmRandom is used for a better rhythm sync between different instruments.
|
||||
*/
|
||||
class Composer(val noteRandom: Random, val rhythmRandom: Random) {
|
||||
|
||||
data class Note(val note: Int, val volume: Float, val time: Int)
|
||||
|
||||
fun composeMusic(random: Random) = listOf<Note>(
|
||||
Note(0, 1.0f, 3),
|
||||
Note(1, 1.0f, 3),
|
||||
Note(2, 1.0f, 3),
|
||||
Note(3, 1.0f, 3),
|
||||
Note(4, 1.0f, 3),
|
||||
Note(5, 1.0f, 3),
|
||||
Note(6, 1.0f, 3),
|
||||
Note(7, 1.0f, 3),
|
||||
val baseTime = arrayOf(5, 5, 3, 3, 4, 4, 2, 2, 10).random(rhythmRandom)
|
||||
val baseNote = noteRandom.nextInt(5..19)
|
||||
|
||||
fun composeMusic() = decorate(
|
||||
(0..rhythmRandom.nextInt(5)).flatMap { composeSection() }
|
||||
)
|
||||
|
||||
fun decorate(notes: List<Note>) = notes.map {
|
||||
if (noteRandom.nextInt(4) == 0) {
|
||||
doDecorate(it)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
|
||||
fun doDecorate(note: Note): Note {
|
||||
var noteVal = note.note
|
||||
if (noteRandom.nextInt(4) == 0) {
|
||||
if (noteRandom.nextBoolean()) {
|
||||
noteVal += 1
|
||||
} else {
|
||||
noteVal -= 1
|
||||
}
|
||||
}
|
||||
var volume = note.volume
|
||||
if (noteRandom.nextInt(4) == 0) {
|
||||
volume *= noteRandom.nextFloat() * 0.8f + 0.6f
|
||||
}
|
||||
return Note(noteVal, volume, note.time)
|
||||
}
|
||||
|
||||
fun composeSection(depth: Int = 0): List<Note> {
|
||||
if (depth < 3 && rhythmRandom.nextBoolean()) {
|
||||
val notes = (0..rhythmRandom.nextInt(3 - depth)).flatMap { composeSection(depth + 1) }
|
||||
if (depth == 2) {
|
||||
return (0..rhythmRandom.nextInt(3)).flatMap { notes }
|
||||
} else {
|
||||
return notes
|
||||
}
|
||||
} else {
|
||||
var notePointer = baseNote + noteRandom.nextInt(-3..3)
|
||||
var direction = -1
|
||||
var directionCounter = 0
|
||||
return (0..rhythmRandom.nextInt(4..16)).map {
|
||||
if (directionCounter == 0) {
|
||||
// start new direction
|
||||
directionCounter = rhythmRandom.nextInt(2..6)
|
||||
direction = if (directionCounter % 2 == 0) {
|
||||
rhythmRandom.nextInt(-2..2)
|
||||
} else {
|
||||
noteRandom.nextInt(-3..3)
|
||||
}
|
||||
}
|
||||
notePointer = abs(notePointer + direction) % 25
|
||||
directionCounter--
|
||||
Note(notePointer, 1.0f, baseTime + rhythmRandom.nextInt(-1..1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ import net.minecraft.world.level.material.MapColor
|
||||
import net.minecraft.world.phys.BlockHitResult
|
||||
import quaedam.Quaedam
|
||||
import quaedam.projector.Projector
|
||||
import quaedam.utils.getChunksNearby
|
||||
import quaedam.utils.sendBlockUpdated
|
||||
|
||||
object CyberInstrument {
|
||||
@ -173,11 +174,24 @@ class CyberInstrumentBlockEntity(pos: BlockPos, state: BlockState) :
|
||||
private fun checkProjections() =
|
||||
Projector.findNearbyProjections(level!!, blockPos, MusicProjection.effect.get()).isNotEmpty()
|
||||
|
||||
fun startMusic() {
|
||||
if (player == null && !level!!.isClientSide && checkProjections()) {
|
||||
fun startMusic(force: Boolean = false, synced: Boolean = false) {
|
||||
if ((player == null || force) && !level!!.isClientSide && checkProjections()) {
|
||||
player = MusicPlayer(level!!.random.nextLong(), level!!, blockPos)
|
||||
setChanged()
|
||||
sendBlockUpdated()
|
||||
if (!synced) {
|
||||
// sync start to other instruments
|
||||
level!!.getChunksNearby(blockPos, 1)
|
||||
.flatMap {
|
||||
it.blockEntities
|
||||
.filterValues { entity -> entity is CyberInstrumentBlockEntity }
|
||||
.filterKeys { pos -> pos.distSqr(blockPos) < 100 }
|
||||
.values
|
||||
}
|
||||
.filterNot { it == this }
|
||||
.filterIsInstance<CyberInstrumentBlockEntity>()
|
||||
.forEach { it.startMusic(force = true, synced = true) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ class MusicPlayer(val seed: Long, val level: Level, val pos: BlockPos, val start
|
||||
tag.getLong(TAG_STARTED_AT)
|
||||
)
|
||||
|
||||
var notes = Composer.composeMusic(Random(seed)).toMutableList()
|
||||
var notes = Composer(Random(seed), Random(startedAt / 20 * 15)).composeMusic().toMutableList()
|
||||
val totalTime = notes.sumOf { it.time }.toLong()
|
||||
var remainingTime = totalTime
|
||||
val isEnd get() = remainingTime <= 0 || notes.isEmpty()
|
||||
|
Loading…
Reference in New Issue
Block a user