with glfw3; use glfw3;
with gl; use gl;
with interfaces.c; use interfaces.c;

with sysutils;
with text_io; use text_io;
with ada.strings.unbounded; use ada.strings.unbounded;

with musical; use musical;


--This package defines a minimalist sound loop capability
--for Linux using the ubiquitous command line sound player
--"aplay" using ALSA sound that handles WAV sound files.
--
--Short & transient sounds are easily handled using a
--"system" shell background command initiator.
--
--Controlling sound loop files, on the other hand,
--requires the ability to interrupt them at odd times, 
--and the ability to replay them indefinitely.
--
--Those interrupts and replays are herein controlled
--using Ada tasking.


package body sndloop is



task body sndtask is

	saplay2 : constant string := "apid.txt";
	saplay1 : constant string := 
		"aplay --nonblock --quiet --process-id-file ";

	--above form of the system call to "aplay" generates
	--a file with a user-specified name that contains
	--the PID (process ID number), with which we may
	--kill it later.  Our name will be "<X>apid.txt"
	--where X will be a character from the set
	--{'a'..'z'}.  See client snd4ada_hpp.adb

	sndFileName: unbounded_string;
	skill : constant string := "/bin/kill ";
	ok: boolean;
	pidstr: musical.idtype; --string(1..99);
	last: natural;
	fid: file_type;
	tdur,tos,tod: gldouble;
	quit: boolean := false;
	tch: character;
	bch: constant character := ' ';

	innerDT: constant duration := 0.10;
	--this adjusts the frequency of the inner loop

	filewait : constant duration := 0.4; --0.25; --sec
	--26jan20 increased from .25 to .4 due to NUC swim crash
	--this seems to allow sufficient time 
	--for system to write the PID file
	--before we try to read it.

	margin: constant gldouble := 0.20;
	--this addition to actual sound duration provides a short
	--dwell between the end of a sound and any subsequent 
	--attempt to replay it.  The replay PID might change.

	music: musictask;

	--debug:
	--debug: constant boolean := false;
	debug: constant boolean := true;
	dfil: file_type;
	dfname: constant string := "sndDbg.txt";

begin

outer:
loop


	select --outer

		--begin music:
		accept Start(name: string; dur: gldouble; ch: character) do
			sndFileName := to_unbounded_string(name);
			tdur:=dur+margin; --sound duration
			tch:=ch; --task id in {'a'..'z'}

			--initiate "aplay" & get tos (TimeOfStart)
			music.Play( saplay1&tch&saplay2&bch&to_string(sndFileName), tos );

		end Start;

		delay filewait; --give system time to write file

		music.getPID( tch&saplay2, pidstr, last ); --BLOCKS HERE

		if debug then
			create(dfil,out_file,tch&dfname);
			put_line(dfil, "sndloop " &tch& " init -------------------------");

			put(dfil,"read: "&saplay1&tch&saplay2&bch&to_string(sndFileName));
			put_line(dfil," : running pid1 : "&pidstr(1..last));
		end if;

		quit:=false;
		inner:
		loop

			select --inner
				accept Stop do --kill music now
					sysutils.Shell( skill&pidstr(1..last), Ok );

					if debug then
						put_line(dfil,"killing : "&pidstr(1..last));
					end if;

					quit:=true;
				end Stop;
			or
				delay innerDT; --controls innerloop frequency
			end select; --inner

			exit inner when quit;

			tod:=glfwGetTime;
			if tod-tos>tdur then --music is over

				music.Play( --reinitiate
					saplay1&tch&saplay2&bch&to_string(sndFileName), tos);

				delay filewait; --give system time to write file

				music.getPID( tch&saplay2, pidstr, last );

				if debug then
					put_line(dfil,"running pid2 : "&pidstr(1..last));
				end if;

			end if;

		end loop inner;

		if debug then
			close(dfil);
		end if;

	or
		terminate;

	end select; --outer


end loop outer;

exception
	when others =>
		if debug then
			close(dfil);
		end if;
		put_line("sndloop.adb error");
		raise;

end sndtask;

end sndloop;

