Hey hamish,
Here it is and merry christmas... the moudule itself is should be easy just to plop in. But there are some things that need to be addressed...
1. when you first plop it in you need to put somewhere a call to function MUS_doAction(weight as float) whenever you fire a gun or do somthing inportant (like maby all of a sudden the boss appears in front of you), weight is how "important" the action is.
2. when you load the playlists, it assumes this is the only "modual" loading the music, and that once the master playlist is loaded that it will never be deleted and reloaded (unless the app is restarted of course)
3. inside the music directory, you need a new folder called "playlists" and another folder called "songs" (for obvious reasons) but if you want to name them somthing different you can change the constants at the top of the module
4. The playlist filetype:
i've attached a sample playlist and here is a definition of what the different lines do (i used the script reader you already have built in)
sample playlist (save as .dpl) - dark play list
!Playlist
playlistTitle: "Test Playlist"
CurrentActionLevel: 1
NumberOfActionLevels: 3
MaxAction: 100
NewActionWeight: 100
ActionDecay: 2.0
CurrentAction: 20
MinimumSongPlaytime: 20
!Action Level
level: 1
!song
File: "isolate.mp3"
title: "isolate"
volume: 100
speed: 100
times Played: 0
!song
File: "testsong1.mp3"
title: "a test song"
volume: 100
speed: 100
times Played: 0
!Action Level
level: 2
!song
File: "testsong2.wav"
title: "Testsong Level 2a"
volume: 100
speed: 100
times Played: 0
!song
File: "testsong3.wav"
title: "Testsong Level 2b"
volume: 100
speed: 100
times Played: 0
!Action Level
level: 3
!song
File: "TestsongA.mid"
title: "Testsong #1"
volume: 100
speed: 100
times Played: 0
!song
File: "TestsongB.mid"
title: "Testsong #2"
volume: 100
speed: 100
times Played: 0
!song
File: "TestsongC.mid"
title: "Testsong #3"
volume: 100
speed: 100
times Played: 0
Definitions:
!playlist ` starts the playlist heading
playlistTitle ` the title of the playlist (not used, but might be later for added functionality/debuging)
CurrentActionLevel `action level you start out on
NumberOfActionLevels ` the number of action levels in the playlist
MaxAction ` this is like "max weight"
NewActionWeight `percent value
ActionDecay ` how fast the action value decays back down to zero (FPS independent)
CurrentAction `starting level "weight"
MinimumSongPlaytime `min play time in seconds
!Action Level `starts a new action level
level `level number of the action level
!song `new song in this action level
File `song file
title `title of the song
volume `indivudual song volume (adjust all songs with the global volume)
speed `how fast a song plays...
times Played `just a preset so that you can make a song be played less times.
5. some last notes:
> you can change how long the songs take to fade between each other by changing the constant
C_SONGFADETIME
> you can disable fading between songs by calling MUS_playEntireSong(C_SONGFADEOFF)
> you can display debuging info by setting the constant
C_MUSICDEBUGON to one
(I'd recomend doing this when your putting it in and playing with the integeration, it will be very helpfull me thinks)
> i didn't include any music caus it would just make this post to big, but all you have to do is plop some music in the directory, add it to the playlist and off you go...
> only one playlist is loaded at the moment, no level switching or main menu yet as far as i know so just change the playlist name to whatever you make yours in the "setupMusic()" function
> post any questions/comments here, i probably check this forum more than my e-mail.
and here's the music module
remstart
MODULE: Music
AUTHOR: Paul Rohde
DATE: December 2004
This module controls the music playing in the game
remend
#constant C_MUSICDIR "Data/Music/songs/"
#constant C_PLAYLISTDIR "Data/Music/Playlists/"
#constant C_MAXACTIONLEVELS 10
#constant C_MAXSONGSPERPLAYLIST 20
#constant C_SONGFADETIME = 5000
#constant C_MASTERPLAYLIST 0
#constant C_ALTERNATEPLAYLIST 1
#constant C_SONGFADEOFF 1
#constant C_SONGFADEON 0
#constant C_MUSICDEBUGON 0
type TYPE_Playlist
playlistTitle as string
curActionLevel as integer
numActionLevels as integer
maxAction as integer
newActionWeight as integer
actionDecay as float
curAction as float
songsStartPos as integer
numSongs as integer
minSongPlayTime as integer
lastSongStartTime as integer
endtype
type TYPE_ActionLevel
songsStartPos as integer
numSongs as integer
endtype
type TYPE_LoadedSong
songNumber as integer
title as string
volume as integer
speed as integer
timesPlayed as integer
endtype
type TYPE_playingSongs
state as integer
name as string
action as integer
songNum as integer
volume as integer
starttime as integer
fadetime as integer
endtype
type TYPE_musicOptions
globalVolume as integer
playFullSong as integer
endtype
declareMusic:
global G_tmpState as integer
global G_activePlaylist as integer
global G_musicOptions as TYPE_musicOptions
global dim G_loadedSongs(1,C_MAXSONGSPERPLAYLIST) as TYPE_LoadedSong
global dim G_actionLevels(1,C_MAXACTIONLEVELS) as TYPE_ActionLevel
global dim G_musicPlaylists(1) as TYPE_Playlist
global dim G_playingSongs(1) as TYPE_playingSongs
return
function setupMusic()
G_playingSongs(0).state = -1
G_playingSongs(1).state = -1
MUS_setGlobalVolume(100)
MUS_loadPlaylist("testPlaylist.dpl", C_MASTERPLAYLIST) `.dpl - DB play list
MUS_setCurrentPlaylist(C_MASTERPLAYLIST)
MUS_playEntireSong(C_SONGFADEON)
endfunction
function unloadMusic()
local i as integer
for i = 0 to 1
MUS_wipePlaylist(i)
next i
endfunction
`----------------------------------------------------------------------------------------------------------
`All functions above this point are the basic update, setup, declare, and unload functions/subroutens
`----------------------------------------------------------------------------------------------------------
`----------------------------------------------------------------------------------------------------------
`THESE ARE THE FUNCTIONS YOU NEED TO USE!!!!
`----------------------------------------------------------------------------------------------------------
`call this function whenever you say fire a gun or do some sort of things that might
`cause the user's heart-rate to go up =)
function MUS_doAction(actionWeight as float)
local tmp as float
tmp = (G_musicPlaylists(G_activePlaylist).newActionWeight / 100.0) * actionWeight
inc G_musicPlaylists(G_activePlaylist).curAction, tmp
if G_musicPlaylists(G_activePlaylist).curAction > G_musicPlaylists(G_activePlaylist).maxAction
G_musicPlaylists(G_activePlaylist).curAction = G_musicPlaylists(G_activePlaylist).maxAction
endif
endfunction
`use this to set the global music volume (100 - full volume - 50 half volume)
`note that this value simply scales the local volume, ex if you set a song to play
`at 200 volume caus it was quiet, and then set the global volume to 50, that song
`would play at 100 volume... cool huh?
function MUS_setGlobalVolume(volume as integer)
G_musicOptions.globalVolume = volume
for i = 0 to 1
if G_playingSongs(i).state = 0
set music volume G_playingSongs(1).songNum, MUS_volumeScale(G_playingSongs(1).volume)
endif
next i
endfunction
`use the constants Default playlist or Master playlist to change the currently playing playlist
function MUS_setCurrentPlaylist(playlistNum as integer)
G_activePlaylist = playlistNum
MUS_playSong(G_activePlaylist, 0, 0)
endfunction
`this toggles either playing an entire song (no changing action levels untill a song is finihed)
`or it will change the song if the action level changes and the minimum play time has been
`acomplished.
function MUS_playEntireSong(toggle as integer)
G_musicOptions.playFullSong = toggle
endfunction
rem this might be the only other function you might need, it loads playlist files(if one is already
rem loaded then it wipes the playlist (including deleting the previously loaded songs)
rem and then loads a whole new playlist.
rem the filename is local to the "playlist" directory
rem number is the "playlist number" so use the constants at the top
`MUS_loadPlaylist(fileName as string, Number as integer)
`----------------------------------------------------------------------------------------------------------
`All functions below this point are "closed" (you don't need to know how they work to use this module)
`----------------------------------------------------------------------------------------------------------
function updateMusic()
MUS_updateActionLevel()
local i as integer
for i = 0 to 1
if G_playingSongs(i).state <> -1
rem check to see if the song is fading out
if G_playingSongs(i).state = 0
MUS_updateFadeOut(i)
if C_MUSICDEBUGON = 1 then text 300,270,"Fading Out: " + G_playingSongs(i).name
endif
rem check to see if the song is simply playing
if G_playingSongs(i).state = 1
MUS_updateSong(i)
endif
rem check to see if the song is fading in
if G_playingSongs(i).state = 2
if C_MUSICDEBUGON = 1 then text 300,300,"Fading In: " + G_playingSongs(i).name
MUS_updateFadeIn(i)
endif
endif
next i
endfunction
function MUS_volumeScale(volume as float)
local tmp as float
local rtrnVol as integer
tmp = G_musicOptions.globalVolume/100.0
rtrnVol = int(tmp*volume)
endfunction rtrnVol
function MUS_updateActionLevel()
rem decay of action levels
dec G_musicPlaylists(G_activePlaylist).curAction, G_musicPlaylists(G_activePlaylist).actionDecay*G_LoopSpeed
if G_musicPlaylists(G_activePlaylist).curAction < 0 then G_musicPlaylists(G_activePlaylist).curAction = 0
rem calculate the new levels
local calculatedLevel as integer
if G_musicPlaylists(G_activePlaylist).curAction >= G_musicPlaylists(G_activePlaylist).maxAction
calculatedLevel = G_musicPlaylists(G_activePlaylist).numActionLevels
else
calculatedLevel = 1+int((G_musicPlaylists(G_activePlaylist).curAction * (G_musicPlaylists(G_activePlaylist).numActionLevels))/G_musicPlaylists(G_activePlaylist).maxAction)
endif
if C_MUSICDEBUGON = 1
text 300,210,"max Action: " + str$(G_musicPlaylists(G_activePlaylist).maxAction)
text 300,225,"current Action Level: " + Str$(G_musicPlaylists(G_activePlaylist).curActionLevel)
text 300,240,"curent Action: " + str$(G_musicPlaylists(G_activePlaylist).curAction)
text 300,255,"calculated Action Level: " + str$(calculatedLevel)
endif
if calculatedLevel <> G_musicPlaylists(G_activePlaylist).curActionLevel
if G_musicOptions.playFullSong = 0 and timer() - G_musicPlaylists(G_activePlaylist).lastSongStartTime >= G_musicPlaylists(G_activePlaylist).minSongPlayTime
G_musicPlaylists(G_activePlaylist).curActionLevel = calculatedLevel
MUS_playSong(G_activePlaylist, calculatedLevel, 0)
endif
endif
endfunction
function MUS_pickActionSong()
local rtrn as integer
local i as integer
local curALevel as integer
local tmpVal as integer
local max as integer
local tmp as integer
curALevel = G_musicPlaylists(G_activePlaylist).curActionLevel
numSongs = G_actionLevels(G_activePlaylist,curAlevel).numSongs
if numSongs > 1
rem long loop statement (not real complicated, Realy...)
for i = G_actionLevels(G_activePlaylist,curAlevel).songsStartPos to G_actionLevels(G_activePlaylist,curAlevel).songsStartPos + numSongs
tmpVal = tmpVal + G_loadedSongs(G_activePlaylist,i).timesPlayed
if G_loadedSongs(G_activePlaylist,i).timesPlayed > max then max = G_loadedSongs(G_activePlaylist,i).timesPlayed
next i
inc max
tmpVal = rnd(tmpVal)
tmp = 0
i = G_actionLevels(G_activePlaylist,curAlevel).songsStartPos
repeat
inc i
if i > G_actionLevels(G_activePlaylist,curAlevel).songsStartPos + numSongs then i = G_actionLevels(G_activePlaylist,curAlevel).songsStartPos+1
if tmpVal >= tmp and tmpVal <= tmp + (max - G_loadedSongs(G_activePlaylist,i).timesPlayed)
rtrn = i
else
tmp = tmp + (max - G_loadedSongs(G_activePlaylist,i).timesPlayed)
endif
until rtrn > 0
else
rtrn = G_actionLevels(G_activePlaylist,curAlevel).songsStartPos
endif
endfunction rtrn
function MUS_updateSong(idx as integer)
rem if the music stoped playing
if music playing(G_playingSongs(idx).songNum) = 0
stop music G_playingSongs(idx).songNum
G_playingSongs(idx).state = -1
G_playingSongs(idx).songNum = 0
G_playingSongs(idx).starttime = 0
G_playingSongs(idx).fadetime = 0
G_playingSongs(idx).action = 0
G_playingSongs(idx).volume = 0
G_playingSongs(idx).name = ""
rem play a new song!
MUS_playSong(G_activePlaylist, G_musicPlaylists(G_activePlaylist).curActionLevel, 0)
else
`set music volume G_playingSongs(idx).songNum, MUS_volumeScale(G_playingSongs(idx).volume)
endif
endfunction
function MUS_updateFadeIn(idx as integer)
if G_playingSongs(idx).starttime + G_playingSongs(idx).fadetime > timer()
local volume as float
volume = (timer() - G_playingSongs(idx).starttime)/(G_playingSongs(idx).fadetime*1.0)
volume = volume*G_playingSongs(idx).volume
if C_MUSICDEBUGON = 1 then text 300,315,"Fade In Volume = " + str$(MUS_volumeScale(volume))
set music volume G_playingSongs(idx).songNum, MUS_volumeScale(volume)
else
G_playingSongs(idx).state = 1
set music volume G_playingSongs(idx).songNum, MUS_volumeScale(G_playingSongs(idx).volume)
endif
endfunction
function MUS_updateFadeOut(idx as integer)
if G_playingSongs(idx).starttime + G_playingSongs(idx).fadetime > timer()
local volume as float
volume = (timer() - G_playingSongs(idx).starttime)/(G_playingSongs(idx).fadetime*1.0)
volume = volume*G_playingSongs(idx).volume
if C_MUSICDEBUGON = 1 then text 300,285,"Fade out Volume = " + str$(MUS_volumeScale(G_playingSongs(idx).volume) - MUS_volumeScale(volume))
set music volume G_playingSongs(idx).songNum, MUS_volumeScale(G_playingSongs(idx).volume) - MUS_volumeScale(volume)
else
set music volume G_playingSongs(idx).songNum, 0
stop music G_playingSongs(idx).songNum
G_playingSongs(idx).state = -1
G_playingSongs(idx).songNum = 0
G_playingSongs(idx).starttime = 0
G_playingSongs(idx).fadetime = 0
G_playingSongs(idx).action = 0
G_playingSongs(idx).volume = 0
G_playingSongs(idx).name = ""
endif
endfunction
rem play a song
function MUS_playSong(playlistNum, actionLevel, song)
rem note that if song is not 0 then it will play a specific song, else it will pick one
rem this function also assumes the references passed to this are valid
local tmpSongIdx as integer = -1
local tmpSongNum as integer
if G_playingSongs(0).state = -1 then tmpSongIdx = 0
if G_playingSongs(1).state = -1 then tmpSongIdx = 1
if tmpSongIdx <> -1
if song <> 0
tmpSongNum = song
else
tmpSongNum = MUS_pickActionSong()
endif
rem state -1 is the "not existing" state
rem state 0 is the "fade out" state
rem state 1 is the "playing" state
rem state 2 is the "fade in" state
G_playingSongs(tmpSongIdx).state = 2
G_playingSongs(tmpSongIdx).action = actionLevel
G_playingSongs(tmpSongIdx).songNum = G_loadedSongs(playlistNum, tmpSongNum).songNumber
G_playingSongs(tmpSongIdx).volume = G_loadedSongs(playlistNum, tmpSongNum).volume
G_playingSongs(tmpSongIdx).name = G_loadedSongs(playlistNum, tmpSongNum).title
G_playingSongs(tmpSongIdx).starttime = timer()
G_playingSongs(tmpSongIdx).fadetime = C_SONGFADETIME
inc G_loadedSongs(playlistNum, tmpSongNum).timesPlayed
play music G_playingSongs(tmpSongIdx).songNum
set music volume G_playingSongs(tmpSongIdx).songNum, 0
rem get the "other" songs index
if tmpSongIdx = 1
tmpSongIdx = 0
else
tmpSongIdx = 1
endif
if G_playingSongs(tmpSongIdx).state <> -1
G_playingSongs(tmpSongIdx).state = 0
G_playingSongs(tmpSongIdx).starttime = timer()
G_playingSongs(tmpSongIdx).fadetime = C_SONGFADETIME
endif
G_musicPlaylists(playlistNum).lastSongStartTime = timer()
endif
endfunction
rem the loading function that loads a playlist
function MUS_loadPlaylist(fileName as string, Number as integer)
local currGroup as string
local tmpSong as integer
`If a valid filename was inputed
if fileName <> ""
`Open this playlist script for parsing
SCT_OpenScript(C_PLAYLISTDIR + fileName)
rem wipe the playlist so there's no extra "dirty" data
MUS_wipePlaylist(Number)
rem loop while there are still lines to read
while SCT_ReadScript()
select G_ScriptLineType
case 1
currGroup = G_ScriptItem(0)
endcase
case 2
select currGroup
case "playlist"
select G_ScriptItem(0)
case "playlisttitle"
G_musicPlaylists(Number).playlistTitle = G_ScriptItem(1)
endcase
case "currentactionlevel"
G_musicPlaylists(Number).curActionLevel = val(G_ScriptItem(1))
endcase
case "numberofactionlevels"
G_musicPlaylists(Number).numActionLevels = val(G_ScriptItem(1))
endcase
case "maxaction"
G_musicPlaylists(Number).maxAction = val(G_ScriptItem(1))
endcase
case "newactionweight"
G_musicPlaylists(Number).newActionWeight = val(G_ScriptItem(1))
endcase
case "actiondecay"
G_musicPlaylists(Number).actionDecay = val(G_ScriptItem(1))/100.0
endcase
case "currentaction"
G_musicPlaylists(Number).curAction = val(G_ScriptItem(1))
endcase
case "minimumsongplaytime"
G_musicPlaylists(Number).minSongPlayTime = val(G_ScriptItem(1))*1000
endcase
endselect
endcase
case "actionlevel"
if G_ScriptItem(0) = "level"
curActionLevel = val(G_ScriptItem(1))
G_actionLevels(Number,curActionLevel).songsStartPos = G_musicPlaylists(Number).songsStartPos + G_musicPlaylists(Number).numSongs
G_actionLevels(Number,curActionLevel).numSongs = 0
endif
endcase
case "song"
select G_ScriptItem(0)
case "file"
if file exist(C_MUSICDIR + G_ScriptItem(1)) = 1
inc G_actionLevels(Number,curActionLevel).numSongs
inc G_musicPlaylists(Number).numSongs
tmpSong = G_actionLevels(Number,curActionLevel).songsStartPos + G_actionLevels(Number,curActionLevel).numSongs
G_loadedSongs(Number, tmpSong).songNumber = freeMusic()
load music C_MUSICDIR + G_ScriptItem(1),G_loadedSongs(Number, tmpSong).songNumber
else
write string logFile, "Music file: " + C_MUSICDIR + G_ScriptItem(1) + " could not be found"
endif
endcase
case "title"
tmpSong = G_actionLevels(Number,curActionLevel).songsStartPos + G_actionLevels(Number,curActionLevel).numSongs
G_loadedSongs(Number, tmpSong).title = G_ScriptItem(1)
endcase
case "volume"
tmpSong = G_actionLevels(Number,curActionLevel).songsStartPos + G_actionLevels(Number,curActionLevel).numSongs
G_loadedSongs(Number, tmpSong).volume = val(G_ScriptItem(1))
if music exist(G_loadedSongs(Number, tmpSong).songNumber)
set music volume G_loadedSongs(Number, tmpSong).songNumber, G_loadedSongs(Number, tmpSong).volume
endif
endcase
case "speed"
tmpSong = G_actionLevels(Number,curActionLevel).songsStartPos + G_actionLevels(Number,curActionLevel).numSongs
G_loadedSongs(Number, tmpSong).speed = val(G_ScriptItem(1))
if music exist(G_loadedSongs(Number, tmpSong).songNumber)
set music speed G_loadedSongs(Number, tmpSong).songNumber, G_loadedSongs(Number, tmpSong).speed
endif
endcase
case "timesplayed"
tmpSong = G_actionLevels(Number,curActionLevel).songsStartPos + G_actionLevels(Number,curActionLevel).numSongs
G_loadedSongs(Number, tmpSong).timesPlayed = val(G_ScriptItem(1))
if G_loadedSongs(Number, tmpSong).timesPlayed < 1 then G_loadedSongs(Number, tmpSong).timesPlayed = 1
endcase
endselect
endcase
endselect
endcase
endselect
endwhile
rem now set some other "default" settings
endif
endfunction
function MUS_wipePlaylist(number as integer)
local i as integer
rem wipe songs
for i = 0 to C_MAXSONGSPERPLAYLIST
if G_loadedSongs(number,i).songNumber > 0
if music exist(G_loadedSongs(number,i).songNumber) = 1
delete music G_loadedSongs(number,i).songNumber
endif
endif
G_loadedSongs(number,i).songNumber = 0
G_loadedSongs(number,i).title = ""
G_loadedSongs(number,i).volume = 0
G_loadedSongs(number,i).speed = 0
G_loadedSongs(number,i).timesPlayed = 0
next i
rem wipe action levels
for i = 0 to C_MAXACTIONLEVELS
G_actionLevels(number,i).songsStartPos = 0
G_actionLevels(number,i).numSongs = 0
next i
rem wipe the rest of the playlist info
G_musicPlaylists(number).playlistTitle = ""
G_musicPlaylists(number).curActionLevel = 0
G_musicPlaylists(number).numActionLevels = 0
G_musicPlaylists(number).maxAction = 0
G_musicPlaylists(number).newActionWeight = 0
G_musicPlaylists(number).actionDecay = 0
G_musicPlaylists(number).curAction = 0
G_musicPlaylists(number).songsStartPos = 0
G_musicPlaylists(number).numSongs = 0
G_musicPlaylists(number).minSongPlayTime = 0
G_musicPlaylists(number).lastSongStartTime = 0
endfunction
Happy listening,
CPU
[center]K-OS Battlefields
IS
///---///---///---UNDER CONSTRUCTION---\\\---\\\---\\\[center]