none
Programa en C++ que reproduzca un mismo archivo de sonido cada 5 minutos hasta que se presione INTRO RRS feed

  • Pregunta

  • Hola buenos días tardes noches o según

    Desearía que por favor me indicasen como puedo construir un programa con esas caracteristicas,

    Tengo alguna ligera idea pero no consigo montar nada en claro

    Tambien desearia que el tiempo pudiera ser variable para poder configurarlo yo mismo si eso es posible

    Muchas gracias por su atención y ayuda

    Inn V. Ginner


    Si una respuesta le resulta util recuerde darle un voto positivo, o marcarla como respuesta. Si yo no fui claro indiqueme donde no lo fui, para que me sea mas facil ayudarle. Tenga un buen dia. Recuerde: Compartir lo que sabe, aprender lo que no sabe

    jueves, 18 de febrero de 2016 17:23

Respuestas

  • Hola.  Veamos si le puedo ayudar un poco más.

    Como tiene conocimiento de C/C++ pero no de Windows, dejaremos de lado la creación de una aplicación de Windows y crearemos una aplicación de consola, como las que usted conoce bien a estas alturas:  Esas cuya función principal es int main() o int main(int argc, char** argv).  ¿Sí?  ¿Le es familiar?  Espero que sí.

    A estas alturas no se ha decidido nada acerca de dónde almacenar el nombre del archivo de sonido o el intervalo.  Eso se lo dejo a usted de tarea.  Yo voy a asumir que esos datos vienen en la línea de comando.  De todas formas, voy a encapsular la funcionalidad en una clase que llamaré Options que no mostraré.  Así cuando usted quiera cambiar la funcionalidad solamente deberá cambiar el código de esa clase.  Espero le sea familiar la programación orientada a objetos en C++.

    Le muestro el prototipo de la clase que almacena las opciones:

    class COptions
    {
    private:
    	//There are 2 options:  Sound interval and sound filename.
    	static tstring _soundFileName;
    	static int _soundInterval;
    
    public:
    	COptions();
    	~COptions();
    
    	//Methods
    	static void Load() throw(std::exception);
    	static const tstring& SoundFileName();
    	static int SoundInterval();
    };

    El tipo de datos tstring lo he definido así:  typedef std::basic_string<TCHAR> tstring;

    A estas alturas debo hacerle notar ese tipo de datos que se usa ahí:  TCHAR.  Windows empezó como un sistema operativo que usaba 1 byte por carácter.  Ahora es capaz de usar 2 bytes por carácter.  TCHAR es simplemente la forma en que el API de Windows mantiene compatibilidad con los programas escritos para 1 byte.

    Y sí, aquí comienza a espesarse el asunto:  Hay que saber the TCHAR y otras cosillas para poder programar para Windows.

    En fin, lo otro que ve es C++ estándar.  La clase std::basic_string es la base para std::string y std::wstring.  Pero volvamos a la clase COptions.

    El método Load() es el encargado de ejecutar la lógica que sea necesaria para cargar las opciones en memoria.

    El método SoundFileName() devuelve un tstring con el nombre del archivo de sonido; el método SoundInterval() devuelve un int con el valor del intervalo, en segundos.

    Con las opciones cargadas podemos escribir el main().  Aquí se espesan las cosas.  Para usar hilos debe saber de hilos y de sincronización.  Si no sabe, pues esto le va a costar.  Si no sabe, lo mejor es que deje esto de lado y lea acerca de programación multihilo en Windows.

    Puesto que no es mi deseo hacer esto por usted, le cuento los pasos a seguir para un main() exitoso.

    1. Cargar las opciones llamando a COptions::Load().  Puesto que el método arroja excepciones de tipo std::exception, debe hacerlo dentro de un try..catch.
    2. Crear un evento de sincronización para señalizar la salida del programa (dejar de esperar X tiempo y sonando el archivo de sonido).  Para esto se usa la función CreateEvent().
    3. Crear un objeto con los datos que usará el hilo de trabajo.  El hilo de trabajo ocupa saber 3 cosas:  El tiempo de espera, el archivo de sonido y el asa al evento creado en el punto #2.  Puede crear una clase para pasar los 3 datos, o puede simplemente pasar el asa del evento y simplemente leer las otras 2 cosas directamente de la clase COptions.
    4. Iniciar el nuevo hilo con _beginthreadex().  Esta función devuelve el asa al hilo de trabajo.  Debe almacenarse para uso posterior.
    5. Pausar y dar opción al usuario de detener el programa.  Lo más fácil es decirle al usuario que presione ENTER para terminar, en cuyo caso usamos un bucle while que invoca la función getchar() para determinar si el usuario presiona ENTER.
    6. Cuando el usuario presiona ENTER el bucle finaliza y se debe señalizar al hilo de trabajo que ya es hora de dejar de trabajar.  Esto se hace con una llamada a SetEvent() usando el asa del evento creado en el paso #2.
    7. Esperamos a que el hilo de trabajo termine con una llamada a WaitForSingleObject() con el asa del hilo de trabajo obtenido en el punto #4.

    Y listo.  Solamente resta crear la función que sirve como entrada al hilo de trabajo.  Le muestro una que usa una clase para pasar los 3 datos al hilo:

    class CWorkerData
    {
    private:
    	int _timeInterval;
    	tstring _soundFileName;
    	HANDLE _exitEvent;
    
    public:
    
    	CWorkerData(int timeInterval, LPCTSTR soundFileName, HANDLE exitEvent) : _timeInterval(timeInterval), _soundFileName(soundFileName), _exitEvent(exitEvent)
    	{
    	}
    
    	~CWorkerData()
    	{
    	}
    
    	int TimeInterval() const
    	{
    		return _timeInterval;
    	}
    
    	const tstring& SoundFileName() const
    	{
    		return _soundFileName;
    	}
    
    	HANDLE ExitEvent() const
    	{
    		return _exitEvent;
    	}
    };
    UINT WINAPI WorkerThreadFunction(LPVOID pArgs)
    {
    	CWorkerData* data = reinterpret_cast<CWorkerData*>(pArgs);
    	if (data)
    	{
    		DWORD result = WAIT_TIMEOUT;
    		while (result == WAIT_TIMEOUT)
    		{
    			result = WaitForSingleObject(data->ExitEvent(), data->TimeInterval() * 1000);
    			if (result == WAIT_OBJECT_0)
    			{
    				//Exit signaled.
    				break;
    			}
    			//Time interval expired.  Play sound.
    			sndPlaySound(data->SoundFileName().c_str(), SND_ASYNC);
    		}
    		delete data;
    	}
    	return 0;
    }


    Y eso sería todo.  Explico rápidamente la última función:  WorkerThreadFunction() recibe como parámetro un objeto de tipo CWorkerData que tiene los 3 valores necesarios:  Intervalo de tiempo, archivo de sonido y asa al evento de salida.

    Lo primero que se hace es que, dentro de un bucle, se usa WaitForSingleObject() para determinar si es hora de dejar de trabajar o no.  Si no lo es, el intervalo de tiempo expirará y el sonido correrá, pero si ya es hora de dejar de trabajar entonces la ejecución se sale del bucle saltándose la llamada a sndPlaySound(), borrando los datos (estándares de programación multihilo) y retornando el valor de 0.


    Jose R. MCP
    Code Samples

    lunes, 14 de marzo de 2016 15:53
    Moderador

Todas las respuestas

  • Hola.  Lamento la demora.  Si no soy yo, prácticamente no hay quién responda preguntas de C++, y yo estaba apartado de los foros desde hace meses.

    En Windows usted puede usar la función sndPlaySound() para reproducir un archivo de sonido.  Luego tenemos el asunto del intervalo de tiempo.  ¿Qué tipo de aplicación desea crear?  ¿Consola o con interfase gráfica?  Si es consola puede crear un nuevo hilo y en ese nuevo hilo usar WaitForSingleObject() para esperar por un evento que señaliza el uso de lta tecla INTRO o bien los 5 minutos (o lo que sea que quiera usar).  Si está usando una interfase gráfica, tiene la misma opción de un hilo pero también tiene la opción de usar la función SetTimer() que posteará un mensaje WM_TIMER al window procedure de la ventana especificada.

    También hay un par de alternativas más para timers.  Puede leer al respecto aquí.

    El intervalo de tiempo e inclusive el archivo de sonido a ejecutar pueden ser configurables, sí.  Solamente debe decidirse acerca del lugar y la forma de almacenar los valores.  Tiene dos opciones:  El registro de Windows o un archivo de texto, idealmente algo bonito como XML.


    Jose R. MCP
    Code Samples

    viernes, 11 de marzo de 2016 15:37
    Moderador
  • Yo lo que quiero hacer es un "algo"(lo que sea) que reproduzca un sonido(a eleccion cada vez) cada 5 minutos o cada 10 

    Si una respuesta le resulta util recuerde darle un voto positivo, o marcarla como respuesta. Si yo no fui claro indiqueme donde no lo fui, para que me sea mas facil ayudarle. Tenga un buen dia. Recuerde: Compartir lo que sabe, aprender lo que no sabe

    viernes, 11 de marzo de 2016 21:20
  • Ok, perfecto.  ¿Cómo anda su conocimiento en C++?  ¿Necesita ayuda con el lenguaje o solamente con las funciones de Windows?  Con mucho gusto le ayudo, pero difícilmente lo haré todo por usted.  Si usted está comenzando en la programación, tal vez debería familiarizarse primero con el lenguaje antes de saltar a cosas como el uso de las funciones de Windows.

    En fin, cuénteme qué sabe y dónde necesita ayuda específicamente y partimos de ahí.


    Jose R. MCP
    Code Samples

    viernes, 11 de marzo de 2016 21:48
    Moderador
  • Tengo un conocimiento decente podemos decir.
    Medio tirando a normal


    Si una respuesta le resulta util recuerde darle un voto positivo, o marcarla como respuesta. Si yo no fui claro indiqueme donde no lo fui, para que me sea mas facil ayudarle. Tenga un buen dia. Recuerde: Compartir lo que sabe, aprender lo que no sabe

    viernes, 11 de marzo de 2016 21:57
  • Lo que no se, es exactamente como empezar o que funciones puedo usar.

    Me explico conozco el funcionamiento de C. Pero no se resolver este problema


    Si una respuesta le resulta util recuerde darle un voto positivo, o marcarla como respuesta. Si yo no fui claro indiqueme donde no lo fui, para que me sea mas facil ayudarle. Tenga un buen dia. Recuerde: Compartir lo que sabe, aprender lo que no sabe

    viernes, 11 de marzo de 2016 21:58
  • Hola.  Veamos si le puedo ayudar un poco más.

    Como tiene conocimiento de C/C++ pero no de Windows, dejaremos de lado la creación de una aplicación de Windows y crearemos una aplicación de consola, como las que usted conoce bien a estas alturas:  Esas cuya función principal es int main() o int main(int argc, char** argv).  ¿Sí?  ¿Le es familiar?  Espero que sí.

    A estas alturas no se ha decidido nada acerca de dónde almacenar el nombre del archivo de sonido o el intervalo.  Eso se lo dejo a usted de tarea.  Yo voy a asumir que esos datos vienen en la línea de comando.  De todas formas, voy a encapsular la funcionalidad en una clase que llamaré Options que no mostraré.  Así cuando usted quiera cambiar la funcionalidad solamente deberá cambiar el código de esa clase.  Espero le sea familiar la programación orientada a objetos en C++.

    Le muestro el prototipo de la clase que almacena las opciones:

    class COptions
    {
    private:
    	//There are 2 options:  Sound interval and sound filename.
    	static tstring _soundFileName;
    	static int _soundInterval;
    
    public:
    	COptions();
    	~COptions();
    
    	//Methods
    	static void Load() throw(std::exception);
    	static const tstring& SoundFileName();
    	static int SoundInterval();
    };

    El tipo de datos tstring lo he definido así:  typedef std::basic_string<TCHAR> tstring;

    A estas alturas debo hacerle notar ese tipo de datos que se usa ahí:  TCHAR.  Windows empezó como un sistema operativo que usaba 1 byte por carácter.  Ahora es capaz de usar 2 bytes por carácter.  TCHAR es simplemente la forma en que el API de Windows mantiene compatibilidad con los programas escritos para 1 byte.

    Y sí, aquí comienza a espesarse el asunto:  Hay que saber the TCHAR y otras cosillas para poder programar para Windows.

    En fin, lo otro que ve es C++ estándar.  La clase std::basic_string es la base para std::string y std::wstring.  Pero volvamos a la clase COptions.

    El método Load() es el encargado de ejecutar la lógica que sea necesaria para cargar las opciones en memoria.

    El método SoundFileName() devuelve un tstring con el nombre del archivo de sonido; el método SoundInterval() devuelve un int con el valor del intervalo, en segundos.

    Con las opciones cargadas podemos escribir el main().  Aquí se espesan las cosas.  Para usar hilos debe saber de hilos y de sincronización.  Si no sabe, pues esto le va a costar.  Si no sabe, lo mejor es que deje esto de lado y lea acerca de programación multihilo en Windows.

    Puesto que no es mi deseo hacer esto por usted, le cuento los pasos a seguir para un main() exitoso.

    1. Cargar las opciones llamando a COptions::Load().  Puesto que el método arroja excepciones de tipo std::exception, debe hacerlo dentro de un try..catch.
    2. Crear un evento de sincronización para señalizar la salida del programa (dejar de esperar X tiempo y sonando el archivo de sonido).  Para esto se usa la función CreateEvent().
    3. Crear un objeto con los datos que usará el hilo de trabajo.  El hilo de trabajo ocupa saber 3 cosas:  El tiempo de espera, el archivo de sonido y el asa al evento creado en el punto #2.  Puede crear una clase para pasar los 3 datos, o puede simplemente pasar el asa del evento y simplemente leer las otras 2 cosas directamente de la clase COptions.
    4. Iniciar el nuevo hilo con _beginthreadex().  Esta función devuelve el asa al hilo de trabajo.  Debe almacenarse para uso posterior.
    5. Pausar y dar opción al usuario de detener el programa.  Lo más fácil es decirle al usuario que presione ENTER para terminar, en cuyo caso usamos un bucle while que invoca la función getchar() para determinar si el usuario presiona ENTER.
    6. Cuando el usuario presiona ENTER el bucle finaliza y se debe señalizar al hilo de trabajo que ya es hora de dejar de trabajar.  Esto se hace con una llamada a SetEvent() usando el asa del evento creado en el paso #2.
    7. Esperamos a que el hilo de trabajo termine con una llamada a WaitForSingleObject() con el asa del hilo de trabajo obtenido en el punto #4.

    Y listo.  Solamente resta crear la función que sirve como entrada al hilo de trabajo.  Le muestro una que usa una clase para pasar los 3 datos al hilo:

    class CWorkerData
    {
    private:
    	int _timeInterval;
    	tstring _soundFileName;
    	HANDLE _exitEvent;
    
    public:
    
    	CWorkerData(int timeInterval, LPCTSTR soundFileName, HANDLE exitEvent) : _timeInterval(timeInterval), _soundFileName(soundFileName), _exitEvent(exitEvent)
    	{
    	}
    
    	~CWorkerData()
    	{
    	}
    
    	int TimeInterval() const
    	{
    		return _timeInterval;
    	}
    
    	const tstring& SoundFileName() const
    	{
    		return _soundFileName;
    	}
    
    	HANDLE ExitEvent() const
    	{
    		return _exitEvent;
    	}
    };
    UINT WINAPI WorkerThreadFunction(LPVOID pArgs)
    {
    	CWorkerData* data = reinterpret_cast<CWorkerData*>(pArgs);
    	if (data)
    	{
    		DWORD result = WAIT_TIMEOUT;
    		while (result == WAIT_TIMEOUT)
    		{
    			result = WaitForSingleObject(data->ExitEvent(), data->TimeInterval() * 1000);
    			if (result == WAIT_OBJECT_0)
    			{
    				//Exit signaled.
    				break;
    			}
    			//Time interval expired.  Play sound.
    			sndPlaySound(data->SoundFileName().c_str(), SND_ASYNC);
    		}
    		delete data;
    	}
    	return 0;
    }


    Y eso sería todo.  Explico rápidamente la última función:  WorkerThreadFunction() recibe como parámetro un objeto de tipo CWorkerData que tiene los 3 valores necesarios:  Intervalo de tiempo, archivo de sonido y asa al evento de salida.

    Lo primero que se hace es que, dentro de un bucle, se usa WaitForSingleObject() para determinar si es hora de dejar de trabajar o no.  Si no lo es, el intervalo de tiempo expirará y el sonido correrá, pero si ya es hora de dejar de trabajar entonces la ejecución se sale del bucle saltándose la llamada a sndPlaySound(), borrando los datos (estándares de programación multihilo) y retornando el valor de 0.


    Jose R. MCP
    Code Samples

    lunes, 14 de marzo de 2016 15:53
    Moderador
  • Vale, muchisimas gracias por su atención. 

    Con esta información sere capaz de construir el programa perfectamente.

    Muchas gracias de nuevo!


    Si una respuesta le resulta util recuerde darle un voto positivo, o marcarla como respuesta. Si yo no fui claro indiqueme donde no lo fui, para que me sea mas facil ayudarle. Tenga un buen dia. Recuerde: Compartir lo que sabe, aprender lo que no sabe

    martes, 15 de marzo de 2016 16:00