Problem z funkcją SNDPlaySound

Problem z funkcją SNDPlaySound
DC
  • Rejestracja:prawie 13 lat
  • Ostatnio:około rok
  • Postów:145
0

Witam. Posiadam problem z funkcją SNDPlaySound. Problem polega na tym, że czasem się ta funkcja mi nie działa, w szczególności po jakimś tam upływie czasu działania mojego programu. Kiedy powinna reagować to nie reaguje.

Do wykorzystania tej procedury mam kilka wątków (każdy inaczej nazwany).
To jest przykład jednego z nich:

Kopiuj
unit Unit12;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Tlhelp32, StdCtrls, PsAPI, Vcl.Samples.Spin, Vcl.ExtCtrls, Math,
  Vcl.Menus, MMSystem;

type
  TPosAlarm = class(TThread)
  private

  protected
    procedure Execute; override;
  end;

 var
  PosAlarm:TPosAlarm;


implementation
uses Unit1;



procedure TPosAlarm.Execute;
begin
  FreeOnTerminate := true;
  while not self.terminated do
begin
SNDPlaySound('PosAlarm.wav', SND_FILENAME OR SND_ASYNC);
sleep(1500);
end;
end;


Initialization
PosAlarm := TPosAlarm.Create(True);

end.

Oczywiście w moim głównym programie mam przygotowany warunek kiedy wywołać funkcję, a więc jest to np. timer z takim czymś:

Kopiuj
if form1.label1.caption = 'xoxoxoxo' then begin PosAlarm.Resume.

Nie wiem jak rozwiązać problem, więc piszę tutaj. Myślałem nad zastosowaniem SNDPlaySound w głównym programie, a nie w jego wątku, ale wtedy podczas działania tej funkcji cały program się zacina.

Proszę o pomoc.

edytowany 1x, ostatnio: flowCRANE
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Tuchów
  • Postów:12167
0

Po pierwsze, użyj funkcji PlaySound – ta której używasz jest subsetem funkcjonalności PlaySound i istnieje wyłącznie ze względu na wsteczną kompatybilność. Po drugie, upewnij się, że wywołania tych funkcji nie nakładają się na siebie i w razie czego zabezpiecz kod w ten sposób:

SND_ASYNC

The sound is played asynchronously and PlaySound returns immediately after beginning the sound. To terminate an asynchronously played waveform sound, call PlaySound with pszSound set to NULL.

Po trzecie, sprawdź, czy wątki faktycznie działają, bo to wcale nie musi być wina omawianej funkcji.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
1

Po mojemu to nie działa gdyż gdzieś w programie zmienia się bieżący folder a nie podajesz pełnej ścieżki do dźwięku, który ma być odtworzony. Poza tym w ogóle nie rozumiem sensu stosowania przy tym wątku.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:5 minut
0

funkcje dźwiękowe to nie moja bajka, ale ....
tworzysz jedną instancję obiektu klasy TPosAlarm ...

Kopiuj
Initialization
    PosAlarm := TPosAlarm.Create(True);
end.

i działasz na tej jednej instancji (wielokrotne resume).

może było by lepiej ..
tworzysz nową instancję wątku dla każdego komunikatu który trzeba odgrać

Kopiuj
if form1.label1.caption = 'xoxoxoxo' then
     newAlarm:=TPosAlarm.create(false);

a wątek się sam się zamyka i zwalnia po odegraniu komunikatu ponieważ ma freeonterminate=true
Jak już ktoś wcześniej wspomniał... wydaje mi się że masz problem z zarządzaniem wątkami a nie z samym odgrywaniem dźwięków z pliku

@kAzek:
folder jest mało ważny, jeśli będzie zły to pewnie nic się nie odtworzy albo rzuci wyjątkiem. Problemem jest użycie do tego wątku, a dokładniej jednej jego instancji i samego sposobu użycia

edytowany 3x, ostatnio: grzegorz_so
GS
@furious programming: kurcze opisałem się edytując ostatniego posta, a Ty skleiłeś wszystko do jednego posta i mam error 404 :)
GS
@furious programming: odczekaj chwilę i nie ingeruj w bieżące (najnowsze) komentarze
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
1

Jeżeli chodzi od wątki do takiego czegoś (choć przecież jeżeli używa parametru SND_ASYNC nie powinny być potrzebne) to w ogóle nie ma co się bawić w TThread tylko korzystać z dobrodziejstw nowszych wersji Delphi i wywoływać po prostu:

Kopiuj
  uses WinApi.MMSystem, System.IOUtils, System.Threading;
  //ciach
  TTask.Run(procedure begin
     SNDPlaySound(PWideChar(TPath.Combine(ExtractFilePath(Application.ExeName), 'PosAlarm.wav'))
       ,SND_FILENAME or SND_ASYNC);
  end)

Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
DC
  • Rejestracja:prawie 13 lat
  • Ostatnio:około rok
  • Postów:145
0

Wiem w czym problem.

Kopiuj
unit Unit14;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Tlhelp32, StdCtrls, PsAPI, Vcl.Samples.Spin, Vcl.ExtCtrls, Math,
  Vcl.Menus, MMSystem;

type
  TPosAlarm = class(TThread)
  private
  protected
    procedure Execute; override;
  end;

type
  TDing= class(TThread)
  private
  protected
    procedure Execute; override;
  end;

type
  TAlarm= class(TThread)
  private
  protected
    procedure Execute; override;
  end;

type
  TMsgAlarm = class(TThread)
  private

  protected
    procedure Execute; override;
  end;

 var
  PosAlarm:TPosAlarm;
  Ding:TDing;
  Alarm:TAlarm;
  MsgAlarm:TMsgAlarm;



implementation
uses Unit1, Unit13;



procedure TPosAlarm.Execute;
begin
  FreeOnTerminate := false;
  while not self.terminated do
begin
SNDPlaySound('PosAlarm.wav', SND_FILENAME OR SND_SYNC);
sleep(1500);
end;
end;

procedure TDing.Execute;
begin
  FreeOnTerminate := false;
  while not self.terminated do
begin
SNDPlaySound('Ding.wav', SND_FILENAME OR SND_SYNC);
sleep(1500);
end;
end;

procedure TAlarm.Execute;
begin
  FreeOnTerminate := false;
  while not self.terminated do
begin
if (strtoint(Form1.Label7.Caption) = 0) then
begin
SNDPlaySound('Danger.wav', SND_FILENAME OR SND_SYNC);
sleep(1500);
end;
end;
end;

procedure TMsgAlarm.Execute;
var
lp, i : integer;
begin
  FreeOnTerminate := false;
  while not self.terminated do
begin
 if Form13.Label1.Caption = 'on' then
begin
SNDPlaySound('Danger.wav', SND_FILENAME OR SND_SYNC);
sleep(1500);
end;
end;
end;




Initialization
PosAlarm := TPosAlarm.Create(True);
Alarm := TAlarm.Create(True);
MsgAlarm := TMsgAlarm.Create(True);
Ding := TDing.Create(True);

end.

W przypadku gdy wyje mi alarm np. PosAlarm i zawyje mi nagle Ding i ja ten ding wyłączę to wtedy gasi się również PosAlarm.
Da się to jakoś oddzielić, żeby jedne nie miało bezpośrednio wpływu na drugie?

edytowany 2x, ostatnio: DroniC
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
0

Funkcje SNDPlaySound ani PlaySound nie potrafią odtwarzać wielu dźwięków na raz dlatego włączenie jednego powoduje wyłączenie drugiego to normalne zachowanie. Użyj wielu dynamicznie tworzonych TMediaPlayer.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
DC
  • Rejestracja:prawie 13 lat
  • Ostatnio:około rok
  • Postów:145
0

Więc do tego będę potrzebować chyba komponent tak? Nigdy nie instalowałem żadnego komponentu xd

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Tuchów
  • Postów:12167
0

Można skorzystać z funkcji PlaySound w celu odtwarzania kilku różnych dźwięków (ale nie jednocześnie) – wystarczy zastosować się do tego co napisałem, czyli przed odtworzeniem nowego dźwięku, wywołać tę funkcję z nilem dla pierwszego parametru. Aktualnie odtwarzany dźwięk zostanie zatrzymany, a nowy będzie mógł być odegrany. Wątki nie są tutaj w ogóle potrzebne.

@DroniC: potrzebujesz odtworzyć kilka dźwięków naraz, czy nie?


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
DC
  • Rejestracja:prawie 13 lat
  • Ostatnio:około rok
  • Postów:145
0
furious programming napisał(a):

Można skorzystać z funkcji PlaySound w celu odtwarzania kilku różnych dźwięków (ale nie jednocześnie) – wystarczy zastosować się do tego co napisałem, czyli przed odtworzeniem nowego dźwięku, wywołać tę funkcję z nilem dla pierwszego parametru. Aktualnie odtwarzany dźwięk zostanie zatrzymany, a nowy będzie mógł być odegrany. Wątki nie są tutaj w ogóle potrzebne.

@DroniC: potrzebujesz odtworzyć kilka dźwięków naraz, czy nie?

Tak fajnie by było odtwarzać kilka dzwięków na raz i móc ingerować w to który ma być wyłączony i kiedy. Niestety korzystając z tego co wysłałem wyżej próbując wyłączyć jeden dzwięk gaszę wszystkie.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 10 godzin
  • Lokalizacja:Tuchów
  • Postów:12167
0

No to dlaczego nie podajesz takich informacji od razu? Marnujemy czas na szukanie dziury w PlaySound, a Ty chcesz ją wykorzystać w sposób, jakiego ona nie obsługuje…

Skorzystaj z podpowiedzi od @kAzek lub użyj jakiejś biblioteki, na przykład BASS.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
1

Z tego co widzę trzeba Ci czegoś takiego (oparte na TMediaPlayer)

Kopiuj
unit uPlayer;


interface

uses Winapi.Windows, Vcl.Forms, Vcl.MPlayer, System.Threading;

type
  TPlayer = class(TObject)
  private
    fMP: TMediaPlayer;
    fPlayRepeat: Boolean;
    fStoped: Boolean;

    procedure MediaPlayerNotify(Sender: TObject);

    procedure SetFileName(AFileName: string);
    function GetFileName: string;
  public
    property FileName: string read GetFileName write SetFileName;
    property PlayRepeat: Boolean read fPlayRepeat write fPlayRepeat;
    procedure Play;
    procedure Stop;
    constructor Create(AFileName: string);
    destructor Destroy; override;
  end;

implementation

procedure TPlayer.MediaPlayerNotify(Sender: TObject);
begin
  TTask.Run(procedure begin
    if fPlayRepeat and (not fStoped) and (TMediaPlayer(Sender).NotifyValue = nvSuccessful) then //aby powtarzał
    begin
      Sleep(1500);
      Play;
    end;
  end)
end;

procedure TPlayer.SetFileName(AFileName: string);
begin
  Stop;
  fMP.FileName:= AFileName;
end;

function TPlayer.GetFileName: string;
begin
  result:= fMP.FileName;
end;

procedure TPlayer.Play;
begin
  Stop;
  if not (fMP.Mode = TMPModes.MPOpen) then
    fMP.Open;
  if (fMP.Mode = TMPModes.MPStopped) or (fMP.Mode = TMPModes.MPPaused) then
    fMP.Play;
  fMP.Notify:= True;
  fStoped:= False;
end;

procedure TPlayer.Stop;
begin
  fStoped:= True;
  if (fMP.Mode = TMPModes.MPPlaying) or (fMP.Mode = TMPModes.MPPaused)  then
    fMP.Stop;
end;

constructor TPlayer.Create(AFileName: string);
begin
  inherited Create;
  fPlayRepeat:= True;
  fStoped:= False;
  fMP:= TMediaPlayer.Create(Application);
  fMP.Visible:= False;
  fMP.Parent:= Application.MainForm;
  fMP.OnNotify:= MediaPlayerNotify;
  fMP.AutoRewind:= True;
  fMP.FileName:= AFileName;
end;

destructor TPlayer.Destroy;
begin
  Stop;
  if (fMP.Mode = TMPModes.MPOpen) then
    fMP.Close;
  //fMP.Free;  Zwolni go TApplication
  inherited Destroy;
end;


end.

To jest cały kod modułu dodaj go do uses i zadeklaruj sobie zmienne typu TPlayer np: PosAlarm: TPlayer i tworzysz PosAlarm:= TPosAlarm.Create('sciezka i nazwa pliku alarm'); tylko tworzysz w takim miejscu gdy już główna forma apki istnieje, bo TMediaPlayer wymaga rodzica (w podobny sposób resztę). Masz metody Play i Stop i chyba to jest tyle co Ci trzeba. Żadnych wątków (w TPlayer jest zaimplementowany wątek ze względu na ten Sleep przed powtórzeniem odtwarzania) tyle odpalasz playery i powinno śmigać a jak nie to pisz i koniecznie wklej kod co zrobiłeś.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
edytowany 3x, ostatnio: kAzek
DC
  • Rejestracja:prawie 13 lat
  • Ostatnio:około rok
  • Postów:145
0

Hm. Skopiowałem cały kod wkleiłem do nowego unitu, a następnie dodałem go do sekcji uses w "głównym" programie. Następnie żeby zobaczyć czy to wgl. działa w buttona dodałem to:

Kopiuj
uPlayer:= TPlayer.Create('ding.wav');

no i nie działa.

Kopiuj
[dcc32 Error] Unit1.pas(1216): E2029 '.' expected but ':=' found
edytowany 1x, ostatnio: flowCRANE
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:3 minuty
  • Lokalizacja:Gorlice
0

Wiesz co przeczytaj jakiś mega podstawowy kurs Delphi bo masakra. uPlayer:= TPlayer.Create('ding.wav'); jak to ma działać jak uPlayer to nazwa modułu...


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)