--
-- Copyright (C) 2020  <fastrgv@gmail.com>
--
-- 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 3 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 may read the full text of the GNU General Public License
-- at <http://www.gnu.org/licenses/>.
--


with ada.directories;
with ada.real_time; use ada.real_time;
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;
	tos,tod, nextTime: time;
	quit: boolean := false;
	tch: character;
	bch: constant character := ' ';

	innerDT: constant time_span := milliseconds(100); --0.10sec
	--this adjusts the frequency of the inner loop

	music1: musictask1;
	music2: musictask2;

	tdur: time_span;

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

begin

outer:
loop


	select --outer

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

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

		end Start;

		music2.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));
			new_line(dfil);
			put_line(dfil," : running pid1 : "&pidstr(1..last));
		end if;

		quit:=false;
		tod:=clock;
		nextTime:=tod+innerDT;
		inner:
		loop

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

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

				quit:=true;
			or
				delay until nextTime; --controls innerloop frequency
				nextTime := nextTime+innerDT;
			end select; --inner

			exit inner when quit;

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

				--music is truly over when this file disappears:
				while ada.directories.exists( tch&saplay2 ) loop
					delay 0.1;
				end loop;

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

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

				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
			put_line(dfil,"sndloop.adb error");
			close(dfil);
		end if;
		raise;

end sndtask;

end sndloop;

