Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Encadenar sonidos???? (https://www.clubdelphi.com/foros/showthread.php?t=37401)

tarco35 12-11-2006 16:29:34

Encadenar sonidos????
 
Saludos a todos... Como puedo reproducir dos sonidos (ficheros waw) de forma consecutiva, o sea, primero uno y cuando termine que reproduzca el otro. Lo he intentado con PlaySound pero el segundo es el unico que se oye...
Gracias por su tiempo y colaboracion...

seoane 12-11-2006 16:42:50

No dices como lo has intentado con PlaySound, así que voy a suponer que utilizaste el parámetro SND_ASYNC, por eso solo se escucha el segundo sonido. Prueba usando el parámetro SND_SYNC, de esta forma la función PlaySound no termina hasta que el sonido se ha reproducido. Es decir:

Código Delphi [-]
  PlaySound('d:\1.wav',0,SND_FILENAME or SND_SYNC);
  PlaySound('d:\2.wav',0,SND_FILENAME or SND_SYNC);

tarco35 12-11-2006 17:22:20

cierto es que el parametro usado es snd_async.. pero no puedo esperar a que snd_sync termine ya que esta funcion la tengo dentro de un cronometro que checa cosas y lanzaria esos sonidos

seoane 12-11-2006 17:24:57

Pensándolo mejor podemos darle otra vuelta de tuerca al código. Estaría bien que el sonido se reproducirá de forma asíncrona al resto del programa, pero manteniendo el orden de reproducción. Así que vamos a utilizar un Thread que se ejecutara el paralelo con el resto de la aplicación, para ello vamos a definir una clase derivada de TThread a la que llamaremos TSound. Esta clase tendrá un método llamado Add que permitirá añadir archivos wav a la lista de reproducción. Por lo demás se comportara como un Thread normal, que podremos pausar y continuar. Vamos con un poco de código:

Código Delphi [-]
type
  TSound = class(TThread)
  private
    FList: TStringList;
    FMutex: THandle;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(Path: String);
  end;


uses mmsystem;

{ TSound }

procedure TSound.Add(Path: String);
begin
  WaitForSingleObject(FMutex, INFINITE);
  try
    FList.Add(Path);
  finally
    ReleaseMutex(FMutex);
  end;
end;

constructor TSound.Create;
begin
  FList:= TStringList.Create;
  FMutex:= CreateMutex(nil,FALSE,nil);
  FreeOnTerminate:= TRUE;
  inherited Create(FALSE);
end;

destructor TSound.Destroy;
begin
  FList.Free;
  CloseHandle(FMutex);
  inherited;
end;

procedure TSound.Execute;
var
  Path: String;
begin
  inherited;
  while not Terminated do
  begin
    WaitForSingleObject(FMutex, INFINITE);
    try
      if FList.Count > 0 then
      begin
        Path:= FList[0];
        FList.Delete(0);
      end else
        Path:= '';
    finally
      ReleaseMutex(FMutex);
    end;
    if Path <> '' then
      PlaySound(PChar(Path),0,SND_FILENAME or SND_SYNC)
    else
      Sleep(10);
  end;
end;


Para utilizarlo, tenemos que crearlo y añadirle archivos a la lista de reproducción. Algo así:
Código Delphi [-]
var
  Sound: TSound;

//Para crearlo
Sound:= TSound.Create;

//Para destruirlo
Sound.Terminate;

//Para añadir un sonido
Sound.Add('d:\1.wav');

Como ves este código es sensiblemente mas complejo que el que puse en el mensaje anterior, puedes usar uno u otro dependiendo de las necesidades de tu aplicación.

EDITO: Corregir un error con la propiedad FreeOnTerminate

seoane 12-11-2006 17:25:47

:D Caramba, parece que te leo el pensamiento

tarco35 12-11-2006 17:29:15

Parece que esto es lo que necesito.... lo pruebo y te confirmo... una cosa... todo el primer codigo descrito es para crear una unidad nueva del proyecto no?

seoane 12-11-2006 17:34:10

Cita:

Empezado por tarco35
Parece que esto es lo que necesito.... lo pruebo y te confirmo... una cosa... todo el primer codigo descrito es para crear una unidad nueva del proyecto no?

Puedes incluirlo en un unit nueva o dentro de la misma unit. Solo tienes que incluir cada cosa en su sitio, es decir, lo que esta debajo de la clausula type ponerlo debajo de la clausula type de tu unit, lo que esa en la clausula uses en la clausula uses y el resto debajo de la clausula implementation.

tarco35 12-11-2006 19:06:52

Lo he hecho haciendolo en una unidad y cuando llamo al procedimiento create me da error. lo he decladado asi:

unit UnidadSonidos;

interface

uses Classes,Windows;

type
TSound = class(TThread)
private
FList: TStringList;
FMutex: THandle;
protected
procedure Execute; override;
public
constructor Create;
destructor Destroy; override;
procedure Add(Path: String);
end;


implementation

{ TSound }
uses MMSystem;

y a partir de aqui como tu me has indicado. En la prmera linea del CREATE me da el error de violacion????

tarco35 12-11-2006 19:08:21

Uso Delphi6 enterprise....(por si sirve de algo)

seoane 12-11-2006 19:13:38

:confused: Exactamente ¿que error te da?

Por otra parte a mi me quedaría una unit mas o menos así:
Código Delphi [-]
unit Unit2;

interface

uses Windows, Classes;

type
  TSound = class(TThread)
  private
    FList: TStringList;
    FMutex: THandle;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Add(Path: String);
  end;

implementation

uses mmsystem;

{ TSound }

procedure TSound.Add(Path: String);
begin
  WaitForSingleObject(FMutex, INFINITE);
  try
    FList.Add(Path);
  finally
    ReleaseMutex(FMutex);
  end;
end;

constructor TSound.Create;
begin
  FList:= TStringList.Create;
  FMutex:= CreateMutex(nil,FALSE,nil);
  FreeOnTerminate:= TRUE;
  inherited Create(FALSE);
end;

destructor TSound.Destroy;
begin
  FList.Free;
  CloseHandle(FMutex);
  inherited;
end;

procedure TSound.Execute;
var
  Path: String;
begin
  inherited;
  while not Terminated do
  begin
    WaitForSingleObject(FMutex, INFINITE);
    try
      if FList.Count > 0 then
      begin
        Path:= FList[0];
        FList.Delete(0);
      end else
        Path:= '';
    finally
      ReleaseMutex(FMutex);
    end;
    if Path <> '' then
      PlaySound(PChar(Path),0,SND_FILENAME or SND_SYNC)
    else
      Sleep(10);
  end;
end;

end.

Me compila y no me da error alguno.

tarco35 12-11-2006 19:17:58

Tal y como acabas de describir tengo la unidad.. y errores de compilacion ninguno, pero cuando realizado la llamada al create me lanza el error ACCESS VIOLATION

seoane 12-11-2006 19:21:37

Estas diciendo que te da un error al ejecutar esta sentencia:

Código Delphi [-]
Sound:= TSound.Create;

Puede parecerte una tontería, pero ¿estas colocando la T delante de Sound?

tarco35 12-11-2006 19:26:51

pues aunque parezca una TonTeria pues parece ser que no lo es .... vaya Tela con T de los ... menso mal que eres un maquina.... mi mas sinceras felicitaciones y muchisimas gracias.... si me das tu email podemos seguir en contacto para cuando me haga falta algo... gracias de nuevo por tu colaboracion
Un saludo.

mancurnino 01-08-2008 23:59:08

¿Hay alguna forma de que estos sonidos que se han añadido a la lista de reproduccion, se reproduzcan uno detras de otro en modo asincrono? Ya que asi, tengo que esperar a que acaben todas las canciones para poder seguir trabajando en la ventana en la que estoy, y me gustaria estar en mi ventana haciendo cosas mientras se va escuchando la lista de reproduccion.

Luego he tenido que poner el metodo Execute en la parte publica porque sino no puedo llamarlo desde otra Unit no?

Gracias¡

seoane 02-08-2008 00:47:03

Cita:

Empezado por mancurnino (Mensaje 305171)
¿Hay alguna forma de que estos sonidos que se han añadido a la lista de reproduccion, se reproduzcan uno detras de otro en modo asincrono? Ya que asi, tengo que esperar a que acaben todas las canciones para poder seguir trabajando en la ventana en la que estoy, y me gustaria estar en mi ventana haciendo cosas mientras se va escuchando la lista de reproduccion.

Luego he tenido que poner el metodo Execute en la parte publica porque sino no puedo llamarlo desde otra Unit no?

A las dos preguntas te respondo con la misma respuesta, la clase TSound que pongo de ejemplo es descendiente de TThread, por lo tanto el método Execute no lo tienes que llamar tu, si no que se llama de forma automática y además se ejecuta en un hilo diferente al principal por lo que es imposible que bloquee ninguna ventana.

Si usas el código tal como lo pongo en el ejemplo no tendrás ningún problema.

mancurnino 02-08-2008 10:00:20

Vale, muchas gracias jeje. Me va bien, creia que para poner la lista en marcha habia que hacer el .execute pero lo hace directamente al añadir una canción y lo ejecuta de forma asincrona y puedo seguir trabajando en la ventana.

Ahora tengo otra pregunta: El caso es que tengo en un resource varias canciones de varios cds; pongo un cd en cada panel y segun elija el cd, me sale un panel u otro con las canciones de ese cd. Bien, por ejemplo en un panel tengo 14 canciones. y cada cancion tiene un boton asociado, es decir:

Código:

procedure TV_Principal.Button1Click(Sender: TObject);
var
  ListaReprod: TSound;
begin
  ListaReprod:= TSound.Create;
  ListaReprod.Add('CD1_1');
  ListaReprod.Add('CD1_2');
  ....
  ListaReprod.Add('CD1_14');
end;

Aqui lo que hace, es algo asi como el reproductor Windows Media Player, que pones una cancion de un cd, y escuchas esa primero, y luego el resto del cd, dando la vuelta como si fuese un loop y volviendose a ejecutar todas las canciones, asi que si por ejemplo pones la cancion 5, te ejecuta desde la 5 hasta la 14 y luego desde la 1 hasta la 5 de nuevo. En el ejemplo que pongo, es la cancion 1, y por lo tanto añado las 14 canciones a la lista, empezando por la 1, pero si hubiese puesto la cancion 5 seria asi:

Código:

procedure TV_Principal.Button5Click(Sender: TObject);
var
  ListaReprod: TSound;
begin
  ListaReprod:= TSound.Create;
  ListaReprod.Add('CD1_5');
  ListaReprod.Add('CD1_6');
  ....
  ListaReprod.Add('CD1_14');
  ListaReprod.Add('CD1_1');
  ListaReprod.Add('CD1_2');
  ListaReprod.Add('CD1_3');
  ListaReprod.Add('CD1_4');
end;

Nose si me explico jeje, supongo que si. El caso es que quiero que haga como el windows media player, que si ejecuto esta cancion numero 5, me ejecute las 14 empezando desde la 5, y cuando me ejecute la ultima, que seria la 4, vuelva a empezar desde la 5, como si iciese otro click en esta cancion numero 5, y que fuese un loop que se repitiese hasta que hiciese click en otra canción.

Haber si puedes ayudarme, gracias¡

mancurnino 02-08-2008 10:21:50

Hola de nuevo, he estado investigando, y me sale algun error:

Por ejemplo al ejecutar una cancion lo que quiero es lo que te he comentado en el comentario anterior, que me pare la lista de reproduccion que se estaba ejecutando (si es que se estaba ejecutando alguna), y que me ejecute la nueva lista relacionada con la cancion de ese boton, por ejemplo la lista que empieza por la cancion numero 5.

¿Como hago para que la lista que se estaba ejecutando, si es que habia alguna, se pare al cambiar de cancion (button), y luego me ejecute la lista de esa cancion?

Hasta ahora lo que he hecho es declarar la lista arriba del todo, y que sea global para toda la unit principal que tengo, de modo que al ejecutar cualquier cancion, ace sus efectos en la misma lista. Ejemplo, las canciones numero 2 y 7:

Código:


procedure TV_Principal.CD1_2Click(Sender: TObject);
begin
  ListaReprod.Terminate;
  ListaReprod:= TSound.Create;
  ListaReprod.Add('CD1_2');
  ListaReprod.Add('CD1_3');
  ListaReprod.Add('CD1_4');
  ListaReprod.Add('CD1_5');
  ListaReprod.Add('CD1_6');
  ListaReprod.Add('CD1_7');
  ListaReprod.Add('CD1_8');
  ListaReprod.Add('CD1_9');
  ListaReprod.Add('CD1_10');
  ListaReprod.Add('CD1_11');
  ListaReprod.Add('CD1_12');
  ListaReprod.Add('CD1_13');
  ListaReprod.Add('CD1_14');
  ListaReprod.Add('CD1_1');
end;
 
procedure TV_Principal.CD1_7Click(Sender: TObject);
begin
  ListaReprod.Terminate;
  ListaReprod:= TSound.Create;
  ListaReprod.Add('CD1_7');
  ListaReprod.Add('CD1_8');
  ListaReprod.Add('CD1_9');
  ListaReprod.Add('CD1_10');
  ListaReprod.Add('CD1_11');
  ListaReprod.Add('CD1_12');
  ListaReprod.Add('CD1_13');
  ListaReprod.Add('CD1_14');
  ListaReprod.Add('CD1_1');
  ListaReprod.Add('CD1_2');
  ListaReprod.Add('CD1_3');
  ListaReprod.Add('CD1_4');
  ListaReprod.Add('CD1_5');
  ListaReprod.Add('CD1_6');
end;

Algo asi es lo que tengo, pero me lo hace mal. La primera vez que pulso un boton, por ejemplo el de la cancion 2, si que me hace la lista y me la reproduce, pero cuando ejecuto la 7 por ejemplo, no me para la lista anterior, y no se me reproduce la nueva. Para pararla pongo .terminate al principio de cada boton, tb he probado con .destroy pero tampoco me va bien, lo que quiero es que el sonido se pare, y se sigue ejecutando, no sé bien que procedure utilizar o como modificar el codigo para que haya una especie de procedure "Stop". Y aparte necesito saber como se puede repetir esta lista de cada boton hasta que cambie de cancion, es decir, que si pulso el boton 2 que me ejecuta la lista de 14 canciones empezando por la 2, me ejecute las 14 una vez, y otra, y otra...

Gracias por la ayuda

mancurnino 03-08-2008 13:41:35

Alguien puede ayudarme cn sto?


La franja horaria es GMT +2. Ahora son las 21:59:07.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi