note
	description: "[
		chocolate doom i_sdlmusic.c
		System interface for music.
	]"
	license: "[
				Copyright (C) 1993-1996 by id Software, Inc.
				Copyright (C) 2005-2014 Simon Howard
				Copyright (C) 2021 Ilgiz Mustafin
		
				This program is free software; you can redistribute it and/or modify
				it under the terms of the GNU General Public License as published by
				the Free Software Foundation; either version 2 of the License, or
				(at your option) any later version.
		
				This program is distributed in the hope that it will be useful,
				but WITHOUT ANY WARRANTY; without even the implied warranty of
				MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
				GNU General Public License for more details.
		
				You should have received a copy of the GNU General Public License along
				with this program; if not, write to the Free Software Foundation, Inc.,
				51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
	]"

class 
	MUSIC_SDL_MODULE

inherit
	MUSIC_MODULE_T

	EXECUTION_ENVIRONMENT

create 
	make

feature {NONE} 

	i_main: I_MAIN

	make (a_i_main: like i_main)
		do
			i_main := a_i_main
		end
	
feature 

	music_initialized: BOOLEAN

	sdl_was_initialized: BOOLEAN

	musicpaused: BOOLEAN

	current_music_volume: INTEGER_32
	
feature 

	Maxmidlength: INTEGER_32
		once
			Result := 96 * 1024
		end
	
feature 

	Music_sdl_module (a_i_main: like i_main): MUSIC_SDL_MODULE
		once
			create Result.make (a_i_main)
		ensure
			instance_free: class
		end

	Sound_devices: ARRAY [INTEGER_32]
			-- List of sound devices that the music module is used for.
		once
			Result := <<{I_SOUND}.snddevice_pas, {I_SOUND}.snddevice_gus, {I_SOUND}.snddevice_waveblaster, {I_SOUND}.snddevice_soundcanvas, {I_SOUND}.snddevice_genmidi, {I_SOUND}.snddevice_awe32>>
		end

	poll
			-- Invoked periodically to poll.
		do
		end

	sdl_is_initialized: BOOLEAN
		local
			freq, channels: INTEGER_32
			format: NATURAL_16
		do
			Result := {SDL_MIXER_FUNCTIONS_API}.mix_query_spec ($freq, $format.to_pointer, $channels) /= 0
		end

	init: BOOLEAN
			-- Initialize music subsystem
		do
			if sdl_is_initialized then
				music_initialized := True
			else
				if {SDL_FUNCTIONS_API}.sdl_init ({SDL_CONSTANT_API}.sdl_init_audio.to_natural_32) < 0 then
					print ("Unable to set up sound.%N")
				elseif {SDL_MIXER_FUNCTIONS_API}.mix_open_audio_device ({I_SOUND}.snd_samplerate, {SDL_AUDIO}.audio_s16sys.to_natural_32, 2, 1024, default_pointer, {SDL_CONSTANT_API}.sdl_audio_allow_frequency_change) < 0 then
					print ("Error initializing SDL_mixer: " + {MIX_ERROR}.get_error)
					{SDL_FUNCTIONS_API}.sdl_quit_sub_system ({SDL_CONSTANT_API}.sdl_init_audio.to_natural_32)
				else
					{SDL_AUDIO_FUNCTIONS_API}.sdl_pause_audio (0)
					sdl_was_initialized := True
					music_initialized := True
				end
			end
			{SDL_MIXER_FUNCTIONS_API}.mix_init ({MIX_INIT_FLAGS_ENUM_API}.mix_init_mid).do_nothing
			if not i_main.I_sound.Snd_musiccmd.is_empty then
				if {SDL_MIXER_FUNCTIONS_API}.mix_set_music_cmd ((create {C_STRING}.make (i_main.I_sound.Snd_musiccmd)).item) < 0 then
					{I_MAIN}.i_error ("Could not Mix_SetMusicCMD " + {MIX_ERROR}.get_error)
				end
			end
			Result := music_initialized
		end

	playsong (a_handle: MIX_MUSIC_STRUCT_API; looping: BOOLEAN)
			-- Start playing a mid
		local
			loops: INTEGER_32
		do
			if music_initialized then
				if attached a_handle as handle or i_main.I_midipipe.midi_server_registered then
					if looping then
						loops := -1
					else
						loops := 1
					end
					if {SDL_MIXER_FUNCTIONS_API}.mix_play_music (a_handle, loops) < 0 then
						{I_MAIN}.i_error ("Could not Mix_PlayMusic " + {MIX_ERROR}.get_error)
					end
				end
			end
		end

	is_mid (mem: MANAGED_POINTER): BOOLEAN
			-- Determine whether memory block is a .mid file
		do
			Result := mem.count > 4 and then mem.item.memory_compare ((create {C_STRING}.make ("MThd")).item, 4)
		end

	registersong (data: MANAGED_POINTER; len: INTEGER_32): detachable MIX_MUSIC_STRUCT_API
			-- Register a song handle from data
			-- Returns a handle that can be used to play the song
		local
			filename: STRING_8
		do
			if music_initialized then
				filename := i_main.M_misc.m_tempfile ("doom.mid")
				if is_mid (data) and data.count < Maxmidlength then
					if not i_main.M_misc.m_writefile_managed_pointer (filename, data) then
						print ("Could not write temp file%N")
					end
				else
					convertmus (data, len, filename)
				end
				Result := {MIX}.mix_load_mus (filename)
				if Result = Void then
					print ("Error loading midi: " + {MIX_ERROR}.get_error)
				end
				if i_main.I_sound.Snd_musiccmd.is_empty then
				end
			end
		end

	convertmus (musdata: MANAGED_POINTER; len: INTEGER_32; filename: STRING_8)
		local
			mus2mid: MUS2MID
		do
			create mus2mid.make (musdata)
			mus2mid.fill_output
			if not i_main.M_misc.m_writefile_list (filename, mus2mid.output) then
				print ("Error writing midi file " + filename)
			end
		end

	stopsong
			-- Stop playing the current song.
		do
			if music_initialized then
				if {SDL_MIXER_FUNCTIONS_API}.mix_halt_music /= 0 then
					{I_MAIN}.i_error ("Could not Mix_HaltMusic")
				end
			end
		end

	resumemusic
			-- Un-pause music
		do
			if music_initialized then
				musicpaused := False
				updatemusicvolume
			end
		end

	updatemusicvolume
			-- SDL_mixer's native MIDI music playing does not pause properly.
			-- As a workaround, set the volume to 0 when paused
		local
			vol: INTEGER_32
		do
			if musicpaused then
				vol := 0
			else
				vol := ((current_music_volume.to_integer_64 * {MIX}.mix_max_volume) // 127).to_integer_32
			end
			vol := {SDL_MIXER_FUNCTIONS_API}.mix_volume_music (vol)
		end

	unregistersong (handle: detachable MIX_MUSIC_STRUCT_API)
			-- Un-register (free) song data
		do
			if music_initialized then
				if attached handle as h then
					{SDL_MIXER_FUNCTIONS_API}.mix_free_music (h)
				end
			end
		end

	shutdown
			-- Shutdown the music subsystem
		do
			if music_initialized then
				if {SDL_MIXER_FUNCTIONS_API}.mix_halt_music /= 0 then
					{I_MAIN}.i_error ("Could not Mix_HaltMusic")
				end
				music_initialized := False
				if sdl_was_initialized then
					{SDL_MIXER_FUNCTIONS_API}.mix_close_audio
					{SDL_FUNCTIONS_API}.sdl_quit_sub_system ({SDL_CONSTANT_API}.sdl_init_audio.to_natural_32)
					sdl_was_initialized := False
				end
			end
		end

	set_music_volume (vol: INTEGER_32)
			-- Set music volume - range 0-127
		do
			current_music_volume := vol
			updatemusicvolume
		end

	pause_music
			-- Pause music
		do
			if music_initialized then
				musicpaused := True
				updatemusicvolume
			end
		end

	music_is_playing: BOOLEAN
			-- Query if music is playing.
		do
			if music_initialized then
				Result := {MIX}.mix_playing_music
			end
		end
	
end -- class MUSIC_SDL_MODULE

Generated by ISE EiffelStudio