Odegranie dwoch dzwiekow rownoczesnie, szczegolnie prosze o

0

Przetrzasajac dzisiaj forum w poszukiwaniu interesujacych rzeczy, :-) natknalem sie na arcyciekawy post pq odnosnie miksowania wavow. Bylbym dozgonnie wdzieczny jesli szanowny pq raczylby podac przyklad w kodzie jak odegrac dwa dzwieki. :-)
Czy mozna jeden dzwiek zapetalic a drugi odgrywac np. po kliknieciu na przycisk?
Chodzi mi tutaj o np. muzyke(zapetla sie) i efekty dzwiekowe(odgrywa sie w momemcie jakiegos zdarzenia).

take care

Wodzu

Ps. a moze jest jakis prosty komponent, ktory do tego sluzy?

0

Jeśli chodzi o komponent do odtwarzania kilku wavow, to najlatwiej by bylo uzyc DelphiX, czyli TDXSound razem z TDXWaveList, do tej listy wgrywasz da wavy, DXSound domyslnie sam sie uaktywnia, a odtworzenie ktoregos dzwieku z listy [we wlasciwosciach elementu mozna ustawic czy ma sie petlic] wyglada chyba jakos tak

DXWaveList1.Items[Nr_wava].Play(False);

Rozwiazanie to jest dobre jesli twoja aplikacja korzysta juz z DirectX [jesli robisz programik, np. typowy program uzytkowy to na kiego grzyba tam DirectX potrzebny wkoncu to nie jest gra]. Wiec wg mnie najlepszym rozwiazaniem bedzie modul BASS [wiem ze niektorzy powiedza ze sie powtarzam, albo ze ten BASS to dziwny jakis]. Co do BASSa to niedlugo pojawi sie moj art o tym module na www.delphi-area.com-------[ Delphi 6 Rulez 4 Ever!, przynajmniej do czasu gdy naucze sie C++ :) ]------

0

No da sie :) ja ci to mowie :D

hehe też chcę znać kod!!!

0

To ja czekam na ten artykul o BASSIE;), poza tym ja robie wlasine gre, wiec muzyka jest tam raczej wskazana...--take care,

Wodzu

0

Moj post pozwalal napisac samemu kod do miksowania dzwiekow. Ale dla leniwcow ponizej zamieszczam program wykorzystujacy wszystkie 3 zaproponowane przeze mnie metody miksowania. Jest duzy: ale sam chciales :))

Jesli chodzi o Twoje potrzeby, sugerowalbym jednak trop Sheitara (DXsound). Mozesz tez zrobic to na na podstawowych komponentach Delphi metoda dwoch MediaPlayerow. Zadziala to nawet na slabych kartach dzwiekowych O ILE ciagly dzwiek (muzyka) bedzie w MIDI a nie w Wave.

Teraz program:

zalozenia:
miksujemy dwa wavy. miksowanie tymi procedurami 3 lub wiecej wavow metoda sekwencyjna (A+B= AB, potem AB+C=ABC) nie da ladnych rezultatow. Lepiej zmodyfikowac procedury.
wavy sa 16bit PCM
maja identyczna czestotliwosc probkowania i liczbe kanalow
sa to 'proste' wavy (bez dodatkowych pol)
nie sa za duze (wszystko dzieje sie w pamieci) uwaga zwlaszcza w wersji z miksem w 32 bitach
pliki sa miksowane 'od poczatku'. tzn jesli chcesz by plik 2 byl wmiksowany w plik1 z offsetem np 1 sekundy, to albo zrob plik2 z sekunda ciszy na poczatku, albo zmodyfikuj procedury sam.

Aha, wiekszosc komentarzy wpisalem juz na forum, wiec moga byc pomylki w {} *

Na formie:
Button1
Button2 (Enabled=false)
Memo1 (do komunikatu o zlym formacie)
RadioGroup z 3 opcjami (3 metody miksowania)
OpenDialog1

Nacisniecie Button1 powoduje dwukrotne otwarcie OpenDialog, w kazdym podajemy JEDEN plik do zmiksowania
jesli naglowki sa ok, pliki sa miksowane wg metody wybranej w radiogroup (0 brutalna z ew. clippingiem, 1 przyciszenie o 50% przed miksem, 2 miks w 32 bitach i przyciszenie potem tyle ile trzeba)
plik wynikowy jest zapisywany w '~tmp.wav'
odegranie miksu: Button2

No to lubudu:

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls, MMSystem;

type
TWaveheader = packed record
RiffID : array [1..4] of char;
RiffLen : LongWord;
WaveID : array [1..4] of char;
FmtID : array [1..4] of char;
FmtLen : LongWord;
FormatTag : Word;
Stereo : Word;
Freq : LongWord;
BytesPSec : LongWord;
BlockAlign : Word;
BitsPer : Word;
DataID : array [1..4] of char;
DataLen : LongWord;
end;

TDataArray = array of smallint;

TForm1 = class(TForm)
Button1: TButton;
OpenDialog1: TOpenDialog;
Button2: TButton;
Memo1: TMemo;
RadioGroup1: TRadioGroup;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
function CheckHeaders(Header1, Header2 :TWaveHeader) :Boolean;
procedure MixBruteForce(var Source1, Source2 : TDataArray);
procedure MixPreAttenuate(var Source1, Source2 : TDataArray);
procedure MixFine(var Source1, Source2 : TDataArray);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

function TForm1.CheckHeaders(Header1, Header2 : TWaveHeader) :Boolean;
*sprawdzenie naglowkow
begin
if (Uppercase(Header1.RiffID)&lt&gt'RIFF') or
(UpperCase(Header2.RiffID)&lt&gt'RIFF') or
(UpperCase(Header1.WaveID)&lt&gt'WAVE') or
(UpperCase(Header2.WaveID)&lt&gt'WAVE') or
(UpperCase(Header1.FmtID)&lt&gt'FMT ') or
(UpperCase(Header2.FmtID)&lt&gt'FMT ') or
(Header1.FmtLen&lt&gt16) or (Header2.FmtLen&lt&gt16) or
(Header1.FormatTag&lt&gt1) or (Header2.FormatTag&lt&gt1) or
(UpperCase(Header1.DataID)&lt&gt'DATA') or
(UpperCase(Header2.DataID)&lt&gt'DATA') or
(Header1.BitsPer&lt&gt16) or (Header2.BitsPer&lt&gt16) or
(Header1.Stereo&lt&gtHeader2.Stereo) or
(Header1.Freq&lt&gtHeader2.Freq) then
Result:=False
else
Result:=True;
end;

{wszystkie 3 procedury miksujace przyjmuja dluzszy dzwiek jako Source1
a krotszy jako Source2 - przestrzegac przy wywolywaniu
wynik jest zwracany w Source1}

procedure TForm1.MixBruteForce(var Source1, Source2 : TDataArray);
*miksowanie z dopuszczeniem clippingu
var
i: integer;
checksum : longint;
begin
for i:=0 to High(Source2) do
begin
CheckSum:=Source1[i]+Source2[i];
if CheckSum&lt-32768 then
Source1[i]:=-32768 *clipping
else
if CheckSum&gt32767 then
Source1[i]:=32767 *clipping
else
Source1[i]:=CheckSum;
end;

end;

procedure TForm1.MixPreAttenuate(var Source1, Source2 : TDataArray);
var
i: integer;

begin
for i:=0 to High(Source1) do
Source1[i]:=Source1[i] div 2; *preatte
nuate 1

for i:=0 to High(Source2) do
inc (Source1[i],(Source2[i] div 2)); *preattenuate 2 and mix

end;

procedure TForm1.MixFine(var Source1, Source2 : TDataArray);
var
i: integer;
checkdata: array of longint; *tu beda dane 32 bit
MaxAbsSum : longint;
Factor: double;

begin
MaxAbsSum:=0;
SetLength(CheckData, Length(Source2));
for i:=0 to High(Source2) do
begin
CheckData[i]:=Source1[i]+Source2[i]; *miksowanie w 32 bitach
if abs(CheckData[i])&gtMaxAbsSum then MaxAbsSum:=abs(CheckData[i]);
end;
if MaxAbsSum&gt32767 then
Factor:=32767/MaxAbsSum * o ile przyciszyc zeby zmiescilo sie w 16 bitach
else
Factor:=1;
for i:=0 to High(Source2) do
Source1[i]:=Round(CheckData[i]*Factor); *przyciszenie zmiksowanego
for i:=Succ(High(Source2)) to High(Source1) do
Source1[i]:=Round(Source1[i]*Factor); *przyciszenie czesci Source1 ktora
* nie jest miksowana bo jest dluzsza
end;

procedure TForm1.Button1Click(Sender: TObject);
var
F, G : file;
HeaderF, HeaderG: TWaveHeader;
DataF, DataG :TDataArray;
begin
if OpenDialog1.Execute and
(UpperCase(ExtractFileExt(OpenDialog1.Filename))='.WAV') then
begin
AssignFile(F, OpenDialog1.FileName);
if OpenDialog1.Execute and
(UpperCase(ExtractFileExt(OpenDialog1.Filename))='.WAV') then
begin
AssignFile(G, OpenDialog1.FileName);
Reset(F,1);
Reset(G,1);
BlockRead(F, HeaderF, 44); *wgranie naglowkow
BlockRead(G, HeaderG, 44);
if not CheckHeaders(HeaderF, HeaderG) then
begin
Memo1.Lines.Add('Wrong format or format mismatch');
CloseFile(F);
CloseFile(G);
Exit;
end;
SetLength(DataF, HeaderF.DataLen div 2); *div 2 po DataLen jest w bajtach
SetLength(DataG, HeaderG.DataLen div 2); * a tablice w smallintach
BlockRead (F,DataF[0],HeaderF.DataLen);
BlockRead (G, DataG[0],HeaderG.DataLen);
CloseFile (F);
CloseFile (G);
AssignFile(F, '~tmp.wav');
Rewrite(F,1);

      if HeaderF.DataLen&gt=HeaderG.DataLen then //ustalenie ktory plik dluzszy
        begin
           case RadioGroup1.ItemIndex of
            0: MixBruteForce(DataF, DataG);
            1: MixPreAttenuate(DataF, DataG);
            2: MixFine(DataF, DataG);
           end;
           BlockWrite(F,HeaderF, 44);
           BlockWrite(F,DataF[0],HeaderF.DataLen);
        end
        else
        begin
           case RadioGroup1.ItemIndex of
            0: MixBruteForce(DataG, DataF);
            1: MixPreAttenuate(DataG, DataF);
            2: MixFine(DataG, DataF);
           end;
           BlockWrite(F,HeaderG, 44);
           BlockWrite(F,DataG[0],HeaderG.DataLen);
        end;

        CloseFile(F);
        Button2.Enabled:=True;
    end;
end;

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
playsound('~tmp.wav', 0, SND_FILENAME or SND_SYNC);
end;

end.
--Pawel

Delphi6

0

Dziekuje bardzo za powyzszy przyklad, zaraz go sprawdze:)
Czy komponent o ktorym pisales, nie spowolni za bardzo aplikacji. jednym slowem, ktora metoda jest wydajniesza?
jeszcze raz dziekuje...
--take care,

Wodzu

0

No, no, Pawel... jestem pod wrazniem :) Obserwuje Twoje poczynania na forum i uwazam, ze jestes na forum najwiekszym "pomagaczem" :)) Naprawde, potrafisz udzielic bardzo sensownej odpowiedzi, z przykladami i wykladem na ten temat ;) Ja juz doszedlem do takiego stopnia lenistwa, ze jak ktos sie mnie o cos pyta to odpowiadam: "Czytaj FAQ", albo "masz o tym artkykul...", albo "juz o tym byla mowa - poszukaj tam i tam"... ;) --Pozdrawiam!
Adam Boduch
www.4programmers.net

0

Dzieki, Adamie, za dobre slowo :-) , ale ja tez czesto odpowiadam czyms w rodzaju:
Zajrzyj tu:
http://www.4programmers.net/forum/index.php?action=show&id=4390

Tu jednak nie moglem tak postapic, bo nie bylo dokad odeslac pytajacego.--Pawel

Delphi6

0

Wodzu napisał:

&gtCzy komponent o ktorym pisales, nie spowolni za bardzo aplikacji. jednym slowem, ktora metoda jest wydajniesza?

MediaPlayer jest powolny. Moze (jesli naprawde nie chcesz uzywac DirectSound) sprobujesz nastepujacej kombinacji : muzyka z MediaPlayera w MIDI (jest trick, zeby ja zapetlic), efekty w wavach odgrywane przez PlaySound--Pawel

Delphi6

1 użytkowników online, w tym zalogowanych: 0, gości: 1