Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A port of an early version of Baystation's new instruments #37447

Open
wants to merge 4 commits into
base: Bleeding-Edge
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions __DEFINES/subsystem.dm
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#define SS_PRIORITY_THERM_DISS 19
#define SS_PRIORITY_AMBIENCE 18
#define SS_PRIORITY_DBCORE 17
#define SS_PRIORITY_MUSIC 16
#define SS_PRIORITY_SUN 3
#define SS_PRIORITY_GARBAGE 2
#define SS_PRIORITY_INACTIVITY 1
Expand Down
32 changes: 32 additions & 0 deletions code/controllers/subsystem/music.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
var/datum/subsystem/music/SSmusic


/datum/subsystem/music
name = "Music"
wait = 1
priority = SS_PRIORITY_MUSIC
flags = SS_NO_INIT | SS_KEEP_TIMING

var/list/datum/musical_event/events = list()

/datum/subsystem/music/New()
NEW_SS_GLOBAL(SSmusic)

/datum/subsystem/music/fire(resumed = FALSE)
if (isemptylist(events))
return
var/list/datum/musical_event/left_events = list()
for (var/datum/musical_event/event in events)
event.time -= wait
if (event.time <= 0)
event.tick()
else
left_events += event
events = left_events

/datum/subsystem/music/proc/push_event(datum/sound_player/source, mob/subject, sound/object, time, volume)
if (istype(source) && istype(subject) && istype(subject) && istype(object) && volume >= 0 && volume <= 100)
src.events += new /datum/musical_event(source, subject, object, time, volume)

/datum/subsystem/music/proc/is_overloaded()
return src.events.len > global.musical_config.max_events
10 changes: 10 additions & 0 deletions code/datums/supply_packs/hospitality.dm
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,13 @@
containername = "big band musical instruments crate"
group = "Hospitality"
containsdesc = "One way around the strange space law is to just order the whole band. Contains one of every instrument."

/datum/supply_packs/synthesizer
contains = list(/obj/structure/synthesized_instrument/synthesizer)
name = "Synthesizer crate"
cost = 50
containertype = /obj/structure/closet/crate/basic
containername = "new age synthesizer crate"
containsdesc = "A new synthesizer has hit the market! Get it while it's still hot!"

group = "Hospitality"
12 changes: 9 additions & 3 deletions code/game/objects/structures/musician.dm
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,13 @@
//to_chat(world, "beat: [beat] / beat length: [length(beat)]")
if(!length(beat)) //This occurs when a comma is at the end of a line
beat = " " //It's intended to be a space so here we make it a space

var/list/notes = splittext(beat, "/")
for(var/note in splittext(notes[1], "-"))
var/delta = length(notes)==2 && text2num(notes[2]) ? text2num(notes[2]) : 1
var/note_str = splittext(notes[1], "-")

var/duration = sanitize_tempo(src.tempo/delta)
for(var/note in note_str)
//to_chat(world, "note: [note]")
if(!playing || shouldStopPlaying(user))//If the instrument is playing, or special case
playing = 0
Expand All @@ -146,10 +151,11 @@
if (ui)
ui.send_message("activeChord", list2params(list(lineCount, chordCount)))
//nanomanager.send_message(src, instrumentObj.name, "activeChord", list(lineCount, chordCount))
if(notes.len >= 2 && text2num(notes[2]))
/*if(notes.len >= 2 && text2num(notes[2]))
sleep(sanitize_tempo(tempo / text2num(notes[2])))
else
sleep(tempo)
sleep(tempo)*/
sleep(duration)
chordCount++

lineCount++
Expand Down
17 changes: 17 additions & 0 deletions code/modules/bayinstruments/docs/Structure.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
This module uses 4 components:
Real instruments -- the physical manifestation of the instrument, the one that is placed in the world
Virtual instruments -- the definition of an instrument, that is, what samples it uses, name and category
Sound player -- used to apply modification to all sounds emitted. Represents the actual source of sound
Synthesized Song - just like /datum/song it's what parses and plays a melody
---
Real instruments inherit from either /obj/structure/synthesized_instrument (static musical instrument) or /obj/item/device/synthesized_instrument (handheld musical instrument)
---
Virtual instruments all inherit from /datum/instrument.
Virtual instruments should follow this structure: /datum/instrument/category_name/instrument_name.

Refer to any file in ./instrument_data to see how it's done.
---
Sound player inherits from /datum/sound_player
---
For synthesized song only use /datum/synthesized_song
---
40 changes: 40 additions & 0 deletions code/modules/bayinstruments/event_manager.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/datum/musical_event
var/sound/object
var/mob/subject
var/datum/sound_player/source
var/time = 0
var/new_volume = 100


/datum/musical_event/New(datum/sound_player/source_, mob/subject_, sound/object_, time_, volume_)
src.source = source_
src.subject = subject_
src.object = object_
src.time = time_
src.new_volume = volume_


/datum/musical_event/proc/tick()
if (!(istype(object) && istype(subject) && istype(source)))
return
if (src.new_volume > 0) src.update_sound()
else src.destroy_sound()


/datum/musical_event/proc/update_sound()
src.object.volume = src.new_volume
src.object.status |= SOUND_UPDATE
if (src.subject)
src.subject << src.object


/datum/musical_event/proc/destroy_sound()
if (src.subject)
var/sound/null_sound = sound(channel=src.object.channel, wait=0)
if (global.musical_config.env_settings_available)
null_sound.environment = -1
src.subject << null_sound
if (src.source || src.source.song)
src.source.song.free_channel(src.object.channel)


244 changes: 244 additions & 0 deletions code/modules/bayinstruments/globals.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
var/global/datum/musical_config/musical_config = new

/datum/musical_config
var/highest_octave = 9
var/lowest_octave = 0

var/highest_transposition = 4
var/lowest_transposition = -4

var/longest_sustain_timer = 50
var/gentlest_drop = 1.07
var/steepest_drop = 10.0

var/channels_per_instrument = 128
var/max_lines = 1000
var/max_line_length = 100
var/max_events = 2400
var/song_editor_lines_per_page = 20

var/usage_info_channel_resolution = 1
var/usage_info_event_resolution = 8

var/env_settings_available = 0
// Keep disabled until I figure out how to preserve environment settings

var/list/env_default = list(7.5, 1.0, -1000, -100, 0, 1.49, 0.83, 1.0, -2602, 0.0007, 200, 0.011, 0.25, 0.0, 0.25, 0.0, -5.0, 5000, 250.0, 0.0, 100, 100, 63)
var/list/list/env_params_bounds = list(
list(1, 100, 1),
list(0, 1, 1),
list(-10000, 0, 1),
list(-10000, 0, 1),
list(-10000, 0, 1),
list(0.1, 20, 1),
list(0.1, 2.0, 1),
list(0.1, 2.0, 1),
list(-10000, 1000, 0),
list(0, 0.3, 1),
list(-10000, 2000, 0),
list(0, 0.1, 1),
list(0.075, 0.25, 1),
list(0, 1, 1),
list(0.04, 4.0, 1),
list(0, 1, 1),
list(-100, 0.0, 1),
list(1000, 20000, 0),
list(20, 1000, 1),
list(0, 10, 1),
list(0, 100, 1),
list(0, 100, 1),
list(0, 256, 0))
var/list/all_environments = list(
"None",
"Generic",
"Padded cell",
"Room",
"Bathroom",
"Living Room",
"Stone Room",
"Auditorium",
"Concert Hall",
"Cave",
"Arena",
"Hangar",
"Carpetted Hallway",
"Hallway",
"Stone Coridor",
"Alley",
"Forest",
"City",
"Mountains",
"Quarry",
"Plain",
"Parking Lot",
"Sewer Pipe",
"Underwater",
"Drugged",
"Dizzy",
"Psychotic",
"Custom")
var/list/env_param_names = list(
"Env. Size",
"Env. Diff.",
"Room",
"Room (High Frequency)",
"Room (Low Frequency)",
"Decay Time",
"Decay (High Frequency Ratio)",
"Decay (Low Frequency Ratio)",
"Reflections",
"Reflections Delay",
"Reverb",
"Reverb Delay",
"Echo Time",
"Echo Depth",
"Modulation Time",
"Modulation Depth",
"Air Absorption (High Frequency)",
"High Frequency Reference",
"Low Frequency Reference",
"Room Rolloff Factor",
"Diffusion",
"Density",
"Flags")
var/list/env_param_desc = list(
"environment size in meters",
"environment diffusion",
"room effect level (at mid frequencies)",
"relative room effect level at high frequencies",
"relative room effect level at low frequencies",
"reverberation decay time at mid frequencies",
"high-frequency to mid-frequency decay time ratio",
"low-frequency to mid-frequency decay time ratio",
"early reflections level relative to room effect",
"initial reflection delay time",
"late reverberation level relative to room effect",
"late reverberation delay time relative to initial reflection",
"echo time",
"echo depth",
"modulation time",
"modulation depth",
"change in level per meter at high frequencies",
"reference high frequency (hz)",
"reference low frequency (hz)",
"like rolloffscale in System::set3DSettings but for reverb room size effect",
"Value that controls the echo density in the late reverberation decay.",
"Value that controls the modal density in the late reverberation decay",
{"
Bit flags that modify the behavior of above properties
•1 - 'EnvSize' affects reverberation decay time
•2 - 'EnvSize' affects reflection level
•4 - 'EnvSize' affects initial reflection delay time
•8 - 'EnvSize' affects reflections level
•16 - 'EnvSize' affects late reverberation delay time
•32 - AirAbsorptionHF affects DecayHFRatio
•64 - 'EnvSize' affects echo time
•128 - 'EnvSize' affects modulation time"})

var/list/echo_default = list(0, 0, 0, 0, 0, 0.0, 0, 0.25, 1.5, 1.0, 0, 1.0, 0, 0.0, 0.0, 0.0, 1.0, 7)
var/list/list/echo_params_bounds = list(
list(-10000, 1000, 0),
list(-10000, 0, 0),
list(-10000, 1000, 0),
list(-10000, 0, 0),
list(-10000, 0, 0),
list(0, 1, 1),
list(-10000, 0, 0),
list(0, 1, 1),
list(0, 10, 1),
list(0, 10, 1),
list(-10000, 0, 0),
list(0, 1, 1),
list(-10000, 0, 0),
list(0, 10, 1),
list(0, 10, 1),
list(0, 10, 1),
list(0, 10, 1),
list(0, 16, 0))
var/list/echo_param_names = list(
"Direct",
"Direct (High Frequency)",
"Room",
"Room (High Frequency)",
"Obstruction",
"Obstruction (Low Frequency Ratio)",
"Occlusion",
"Occlusion (Low Frequency Ratio)",
"Occlusion (Room Ratio)",
"Occlusion (Direct Ratio)",
"Exclusion",
"Exclusion (Low Frequency Ratio)",
"Outside Volume (High Frequency)",
"Doppler Factor",
"Rolloff Factor",
"Room Rolloff Factor",
"Air Absorption Factor",
"Flags")
var/list/echo_param_desc = list(
"direct path level (at low and mid frequencies)",
"relative direct path level at high frequencies ",
"room effect level (at low and mid frequencies)",
"relative room effect level at high frequencies",
"main obstruction control (attenuation at high frequencies)",
"obstruction low-frequency level re. main control",
"main occlusion control (attenuation at high frequencies)",
"occlusion low-frequency level re. main control",
"relative occlusion control for room effect",
"relative occlusion control for direct path",
"main exlusion control (attenuation at high frequencies)",
"exclusion low-frequency level re. main control",
"outside sound cone level at high frequencies",
"like DS3D flDopplerFactor but per source",
"like DS3D flRolloffFactor but per source",
"like DS3D flRolloffFactor but for room effect",
"multiplies AirAbsorptionHF member of environment reverb properties.",
{"
Bit flags that modify the behavior of properties•1 - Automatic setting of 'Direct' due to distance from listener
•2 - Automatic setting of 'Room' due to distance from listener
•4 - Automatic setting of 'RoomHF' due to distance from listener"})

var/list/n2t_int = list() // Instead of num2text it is used for faster access in n2t
var/list/free_channels = list() // Used to take up some channels and avoid istruments cancelling each other
var/free_channels_populated = 0
var/list/nn2no = list(0,2,4,5,7,9,11) // Maps note num onto note offset


/datum/musical_config/proc/n2t(key) // Used instead of num2text for faster access in sample_map
if (!src.n2t_int.len)
for (var/i=1, i<=127, i++)
src.n2t_int += num2text(i)

if (key==0)
return "0" // Fuck you BYOND
if (!isnum(key) || key < 0 || key>127 || round(key) != key)
CRASH("n2t argument must be an integer from 0 to 127")
return src.n2t_int[key]


/datum/musical_config/proc/environment_to_id(environment)
if (environment in src.all_environments)
return src.all_environments.Find(environment) - 2
return -1


/datum/musical_config/proc/id_to_environment(id)
if (id >= -1 && id <= 26)
return src.all_environments[id+2]
return "None"


/datum/musical_config/proc/index_to_id(index)
return max(min(index-2, 26), -1)


/datum/musical_config/proc/is_custom_env(id)
return id_to_environment(id) == src.all_environments[28]


/datum/sample_pair
var/sample
var/deviation = 0

/datum/sample_pair/New(sample_file, deviation)
src.sample = sample_file
src.deviation = deviation
Loading
Loading