--Welcome. I've written this code myself and heavily improved and fixed it with the help of Angelo234! Lots of Thanks to him!! I've marked sections of his code.
--Anyways, you're probably here because you want to add you own music, which is fair enough, the Beam music isn't all thaat exiting
--There are instructions in form of notes all over the file. If you experience any issues, feel free to contact me under Inn0centJok3r on BeamNG.com 
--I hope the notes are helpful enough to allow you to get your stuff working. Have a nice day!

--Please read all notes.

local M = {}

local sfx_table = {} --For caching the played music

local songName = "Radio Off"

local songLimit = 2	        -- Количество песен в плейлисте 
local listLimit = 1		-- Количество плейлистов

local volume = 11
local song = 0
local list = 1
local timer = 0
local musicList = "Default Music"
local author = "Unknown"
local play_song_dir = nil
local inputBlock = false
local need_to_create_sfx = false
local current_sfx_playing = nil
local song_dir = nil
local volumeChanged = false
local volumeChangedTimer = 0
local timermusic = 0
local timerrunning = false
local songchanged = false
local song_dir_cache = nil
local autoplaytimer = 0
local songLength = 0
local autoplay = true
local autoplaySetting = true
local soundNode = 109
local buttonPress

local function playList()

	if list == 1 then
	musicList = "Default Music"
	
		if song == 0 then 
			songName = "How did you do this?"
			play_song_dir  = nil
			author = "Unknown"
			autoplay = false
			songLength = 0

		elseif song == 1 then
			songName = "ЗВУК РАБОТЫ ПЫЛЕСОСА"                                   --Название трека
			play_song_dir  = "pilesos_USER_MUSIC/pilesos"               --Директория куда кидать музыку, после "/" нужно вписать название, как тут jazz
			author = "t.me@m0dsbeamng"      --Автор
			autoplay = true                                           --тут ничё лучше не менять
			songLength = 164		                          --Длина песни в секундах (то есть трек длиной 3 минуты = 180 секунд)

		elseif song == 2 then
			songName = "ПЦ АЭЪ АЭЪ ЭАЪ ЭАЪ АЭЪ АЭЪ ЪАХ ЪАХ ЪАХ"
			play_song_dir  = "pilesos_USER_MUSIC/morgen"
			author = "t.me@m0dsbeamng"
			autoplay = true
			songLength = 171		

				
		end

	elseif list == 2 then
	musicList = "UserMusic" --Feel free to change the playlist name. To add more lists, you can just copy paste this one here to the spot marked --X and then change listLimit=2 to 3 or whichever	
															--... amount of lists that you want to add.
		if song == 0 then 
			songName = "How did you do this?"
			play_song_dir  = nil
			author = "Unknown"
			autoplay = false
			songLength = 0
		end

		--X new playlists -underneath- this point here! Make sure to NOT place anything UNDER the "end"
		
        elseif list == 3 then
	musicList = "UserMusic2" --Feel free to change the playlist name. To add more lists, you can just copy paste this one here to the spot marked --X and then change listLimit=2 to 3 or whichever	
															--... amount of lists that you want to add.
		if song == 0 then 
			songName = "How did you do this?"
			play_song_dir  = nil
			author = "Unknown"
			autoplay = false
			songLength = 0

		elseif song == 1 then
			songName = "Sicko Mode"
			play_song_dir  = "art/sound/music/sickomode"
			author = "Unknown"
			autoplay = true
			songLength = 302		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 2 then
			songName = "Goosepumps"
			play_song_dir  = "art/sound/music/goosebumps"
			author = "Unknown"
			autoplay = true
			songLength = 243		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 3 then
			songName = "Money Trees"
			play_song_dir  = "art/sound/music/moneytrees"
			author = "Unknown"
			autoplay = true
			songLength = 374		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 4 then
			songName = "Ez come Ez go"
			play_song_dir  = "art/sound/music/ezcome"
			author = "Unknown"
			autoplay = true
			songLength = 249		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 5 then
			songName = "Drop top"
			play_song_dir  = "art/sound/music/droptop"
			author = "Unknown"
			autoplay = true
			songLength = 168	--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 6 then
			songName = "rollin"
			play_song_dir  = "art/sound/music/rovingangster"
			author = "Unknown"
			autoplay = true
			songLength = 264		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 7 then
			songName = "My Hood"
			play_song_dir  = "art/sound/music/myhood"
			author = "Unknown"
			autoplay = true
			songLength = 271		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 8 then
			songName = "bawitdaba"
			play_song_dir  = "art/sound/music/bawitdaba"
			author = "Unknown"
			autoplay = true
			songLength = 265		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 9 then
			songName = "Ballin"
			play_song_dir  = "art/sound/music/ballin"
			author = "Unknown"
			autoplay = true
			songLength = 180	--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!

		elseif song == 10 then
			songName = "Your Song Name Here"
			--play_song_dir  = "art/sound/music/YOUR FILE NAME HERE"
			author = "Unknown"
			autoplay = true
			songLength = 60		--Length of the song in seconds, PLEASE ENTER THIS INFORMATION TO USE THE AUTOPLAY FEATURE!!
		end

		--X new playlists -underneath- this point here! Make sure to NOT place anything UNDER the "end"
		
	end
end
--No need to change anything below here. Unless you know what you're doing

--Code by Angelo234 start

local function loadSong(song_dir)
    --If SFX source is not cached (has never been played), then create SFX source
    if not sfx_table[song_dir] then
        sfx_table[song_dir] = obj:createSFXSource(song_dir, "AudioDefaultLoop3D", "", soundNode)
        return true
    end
  
    return false
end

local function playSong(song_dir)
    --Stop current music
    if current_sfx_playing then
		obj:setVolumePitch(current_sfx_playing, 0, 1)
        obj:stopSFX(current_sfx_playing)
    end
 
    --Play new song
    local sfx_to_play = sfx_table[song_dir]
  
    obj:setVolumePitch(sfx_to_play, volume, 1)
    obj:playSFX(sfx_to_play)
  
    current_sfx_playing = sfx_to_play
end

--Code by Angelo234 end

local function moreVol()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if volume <= 9 then
		volume = volume + 1
		guihooks.message("Radio Volume: " .. volume, 4, "vehicle.vertexRadio.volumeState", "volume_up") 
			if current_sfx_playing then
				obj:setVolumePitch(current_sfx_playing, (volume * 0.6), 1)
			end
		end
		
		if volume >= 10 then
		guihooks.message("Max Radio Volume: " .. volume, 4, "vehicle.vertexRadio.volumeState", "volume_up") 
			if current_sfx_playing then
				obj:setVolumePitch(current_sfx_playing, (volume * 0.6), 1)
			end
		end

		volumeChanged = true
		volumeChangedTimer = 0
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.volumeState", "do_not_disturb_alt")
	end
end

local function lessVol()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if volume >= 1 then
		volume = volume - 1
		guihooks.message("Radio Volume: " .. volume, 4, "vehicle.vertexRadio.volumeState", "volume_down") 
			if current_sfx_playing then
				obj:setVolumePitch(current_sfx_playing, (volume * 0.6), 1)
			end
		end
		
		if volume == 0 then
		guihooks.message("Lowest Radio Volume: " .. volume, 4, "vehicle.vertexRadio.volumeState", "volume_mute") 
			if current_sfx_playing then
				obj:setVolumePitch(current_sfx_playing, (volume * 0.6), 1)
			end
		end

		volumeChanged = true
		volumeChangedTimer = 0
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.volumeState", "do_not_disturb_alt")
	end
end


local function nextSong()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if inputBlock == false then		--Blocking input for a small amount of time to prevent user from spamming the function and causing a lua error
			if song >= songLimit then
				song = 1
			else
				song = song + 1
			end
			if song ~=0 then
			autoplay = false
			playList()
			guihooks.message("Next song playing. Now playing: " .. songName .. " (" .. song .. "/" .. songLimit .. ")" .. " -by " .. author, 4, "vehicle.vertexRadio.songState", "volume_up") 
				if electrics.values['reverseactive'] == 0 then	--infotainment screen stuff
					timerrunning = true
					electrics.values['musicscreenactive'] = 1
					songchanged = true
				end
			end	
		end
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.songState", "do_not_disturb_alt")
	end
end

local function pastSong()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if song ~=0 then
		song = song - 1
			if song == 0 then
				guihooks.message("Radio off", 4, "vehicle.vertexRadio.songState", "volume_off") 
				autoplay = false
				songName = "Radio Off"
				obj:stopSFX(current_sfx_playing)
				songLength = 0
			end
		end

		if song ~=0 then
		autoplay = false
		playList()
		guihooks.message("Past song playing. Now playing: " .. songName ..  " (" .. song .. "/" .. songLimit .. ")" .. " -by " .. author, 4, "vehicle.vertexRadio.songState", "volume_up") 
			if electrics.values['reverseactive'] == 0 then
				timerrunning = true
				electrics.values['musicscreenactive'] = 1
				songchanged = true
			end
		end	
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.songState", "do_not_disturb_alt")
	end
end

local function pastSongList()
	autoplay = false
	playList()
	song_dir_cache = sfx_table[song_dir]
	songName = "Radio Off"
	if current_sfx_playing then
		obj:setVolumePitch(current_sfx_playing, 0, 0)
		obj:stopSFX(current_sfx_playing)
	end
end

local function nextList()  

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if list >= listLimit then			
			list = 1
		else
			list = list + 1
		end 		
		song = 0
		pastSongList()
		guihooks.message("Next Playlist selected: " .. musicList .. " (" .. list .. "/" .. listLimit .. ")", 4, "vehicle.vertexRadio.listState", "toc") 
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.listState", "do_not_disturb_alt")
	end
end
	
local function pastList()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if electrics.values.ignitionLevel > 0 then
		if list ~=1 then
			list = list - 1
			song = 0
			pastSongList()
			guihooks.message("Past Playlist selected: " .. musicList .. " (" .. list .. "/" .. listLimit .. ")", 4, "vehicle.vertexRadio.listState", "toc") 
		end
	else
		guihooks.message("Turn on ignition first", 4, "vehicle.vertexRadio.listState", "do_not_disturb_alt")
	end
end

local function autoplay()
	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	if autoplaySetting == false then
		guihooks.message("Autoplay enabled", 4, "vehicle.vertexRadio.autoplay", "toc") 
		autoplaySetting = true
	else
		guihooks.message("Autoplay disabled", 4, "vehicle.vertexRadio.autoplay", "toc") 
		autoplaySetting = false
	end
end
local function turnOff()

	buttonPress = buttonPress or sounds.createSoundscapeSound("ButtonPress")
    sounds.playSoundSkipAI(buttonPress)
	autoplay = false
	song = 0
	playList()
	song_dir_cache = sfx_table[song_dir]
	songName = "Radio Off"
	guihooks.message("Radio off", 4, "vehicle.vertexRadio.songState", "volume_off") 
	if current_sfx_playing then
		obj:setVolumePitch(current_sfx_playing, 0, 0)
		obj:stopSFX(current_sfx_playing)
	end
end

local function updateGFX(dt)
--Code by Angelo234 start
    if play_song_dir then
  
        --Check if we need to create SFX source
        if timer == 0 then
            need_to_create_sfx = loadSong(play_song_dir)
        end     
      
        --If needed to create SFX source
        --then start timer to delay playing song
        if need_to_create_sfx then
			inputBlock = true
            timer = timer + dt
        else
            timer = 0.1
			inputBlock = false
        end
  
        --If arbitrary amount of time passed then play song
        if timer >= 0.1 then
            playSong(play_song_dir)
            timer = 0
			inputBlock = false
            play_song_dir = nil
        end
    end
--Code by Angelo234 end

--Automatically turn off any music when ignition is turned off while some is playing
	if electrics.values.ignitionLevel == 0 and song ~= 0 then
		turnOff()
	end
	
--stuff for center screen
	if volumeChanged == true then
		volumeChangedTimer = volumeChangedTimer + dt
		if volumeChangedTimer >= 3 then
			volumeChanged = false
			volumeChangedTimer = 0
		end
	end
--Autoplay
--print("RADIO DEBUG: automplaytimer: " .. autoplaytimer)
	if songLength > 0 then
		autoplaytimer = autoplaytimer + dt
		if autoplay == true and autoplaySetting == true then
			if autoplaytimer >= songLength then
				nextSong()
			end
		elseif autoplaytimer >= songLength then
			autoplaytimer = 0
		end
	else
		autoplaytimer = 0
	end
--stuff for the infotainment screen
	if electrics.values['reverseactive'] == 1 then	
		timermusic = 0
		songchanged = false
		timerrunning = false
	end 
	
	if timerrunning == true and electrics.values['reverseactive'] == 0 then
		timermusic = timermusic + dt
		
		if songchanged == true then
			autoplaytimer = 0
			timermusic = 0
		    songchanged = false
		end	
		
		if timermusic >= 5 then
		electrics.values['musicscreenactive'] = 0
		timerrunning = false
		timermusic = 0
		end
	end
	electrics.values["volumeChanged"] = volumeChanged
	electrics.values["radioAuthor"] = author
	electrics.values["radio"] = songName
	electrics.values["radioVolume"] = volume
end

local function onInit()

	if electrics.values["isSimpleTrafficCar"] then
		M.updateGFX = nop
		M.onReset = nop
		return
	end

	for v, node in pairs (v.data.nodes) do	--for finding out the node ID
		if node.name == "int3" then	
			soundNode = v
		end
	end
	volume = 3
	song = 0
	list = 1
	timer = 0
	songName = "Radio Off"
	musicList = "Default Music"
	author = "Unknown"
	play_song_dir = nil
	inputBlock = false
	need_to_create_sfx = false
	current_sfx_playing = nil
	electrics.values['musicscreenactive'] = 0
	song_dir = nil
	volumeChanged = false
	volumeChangedTimer = 0
	autoplaytimer = 0
	timermusic = 0
	timerrunning = false
	songchanged = false
	songLength = 0
end

local function onReset()

 if song == 0 and current_sfx_playing then	--To disable all previously played music that stats playing upon reset for unknown reasons
	song = 1
	playList()
	song_dir = play_song_dir
	if song_dir_cache == nil and sfx_table[song_dir] ~= nil then
		song_dir_cache = sfx_table[song_dir]
		obj:setVolumePitch(song_dir_cache, 0, 1)
		obj:stopSFX(song_dir_cache)
		play_song_dir = nil
		inputBlock = false
		need_to_create_sfx = false
		current_sfx_playing = nil
		song = 0
		songName = "Radio Off"
		musicList = "Default Music"
		author = "Unknown"
	elseif song_dir_cache ~= nil then
		obj:setVolumePitch(song_dir_cache, 0, 1)
		obj:stopSFX(song_dir_cache)
		play_song_dir = nil
		inputBlock = false
		need_to_create_sfx = false
		current_sfx_playing = nil
		song = 0
		songName = "Radio Off"
		musicList = "Default Music"
		author = "Unknown"
	else
		song = 0
		songName = "Radio Off"
		musicList = "Default Music"
		author = "Unknown"
	end
 end
end

-- public interface
M.nextSong = nextSong
M.pastSong = pastSong
M.nextList = nextList
M.pastList = pastList
M.lessVol = lessVol
M.moreVol = moreVol
M.playList = playList
M.autoplay = autoplay
M.turnOff = turnOff
M.onInit    = onInit
M.onReset    = onReset
M.updateGFX = updateGFX
return M
