| Autor |
Beitrag |
Andreas Pfau
      
Beiträge: 997
|
Verfasst: Do 20.03.03 21:54
Hallo,
kennt ihr das, wenn ihr mit WaveOutWrite() (oder sonst 'ne Prozedur) eine Wave loopt, und das dann abbrecht? Das knistert! Klar, die Lautsprechermembran fällt abrupt zurück, wenn die Wave-Position nicht grade zufällig bei +-0 ist. Aber das ist nicht immer gegeben. Ich will einen Frequenzgeneartor schreiben, der kurze (~ 100µs...100ms) Sequenzen loopt. Ich kann das Loop einfach zu Ende spielen lassen, aber wenn's mal 100ms sind, dauert das zu lange. Und beim verändern der Frequenz soll's nicht knacken. Wie würdet ihr vorgehen?
_________________ Life is a bad adventure, but the graphic is really good!
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Do 20.03.03 22:14
das generelle Problem mit dem Knistern hatte ich auch mal, aber du erzeugst ja deine Sounds selbst und liest sie nicht aus Waves, also ist dein Problem ein anderes.
Es gibt Verfahren, die die Amplitude langsam runterregeln. Wenn man also vorher bei 100mV war, was die Membran anspannt, dann wird ganz langsam auf 0mV runtergeregelt, wodurch die Membran nicht abrupt zurückfällt, sondern eben nicht ganz so abrupt. Wie das genau funktioniert, weiß ich nicht, da ich nicht wieß, wie man Wave-Signale selbst erzeugt, aber auf jeden fall wird diese Technik des öfteren angewandt. Ob's noch was anderes gibt, weiß ich nicht.
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Do 20.03.03 23:01
Ähem... du hast Recht, das Verfahren ist einleuchtend, da bin iach auch schon draufgekommen. Aber du scheinst das nicht zu verstehen, daher erkläre ich die die genaue Problematik:
- Ich erzeuge eine Periode von z.B. einer Sinusfunktion
- Dann loope ich sie mit WaveOutWrite()
- Beim beenden kann sein, dass die Asugabe grade bei 100mV ist
- Also verwende ich statt WaveOutReset() WaveOutBreakLoop(), dadurch, wird die aktuelle Periode fertiggespielt (jede Periode endet bei Null)
Das Problem: Wenn die Periode lange dauert (z.b. bei 10Hz -> 100ms), dann würde es ewig dauer, bis der Schieberegler für die Frequenz nach oben verschoben ist, da ich bei jedem pixle Bewegung 100ms verschwende.
Um deine Methode anzuwenden, müsste ich in Echtzeit (also in, sagen wir mal, 10µs) abfragen, wo das Signal steht, dann ein Signal erzeugen, laden, abspielen. Hoffnungslos. Das dauert vorneweg 1ms.
Was mir helfen würde: Das Signal aus mehreren Teilen zusammensetzen, und diese loopen. Wenn jeder Teil maximal 5ms hat, könnte ich den Loop also in 5ms unterbrechen. Aber wie mache ich das? Mit WaveOutXXX() natürlich.
_________________ Life is a bad adventure, but the graphic is really good!
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Fr 21.03.03 22:00
Ich weiß wieder nicht, ob dir das jetzt hilft oder nicht, aber mehrere Chunks loopst du, indem du im WAVEHDR als Flag nicht WHDR_BeginLoop und WHDR_EndLoop gleichzeitig benutzt, sondern im ersten WHDR_BeginLoop und im letzten WHDR_EndLoop. Im ersten Block muss dann die Anzahl an Loops angegeben werden. Alle dazwischenliegenden Blöcke werden dann an einem Stück geloopt (laut SDK). Du erzeugst also eine ausreichende Anzahl an WAVEHDR-Strukturen und füllst sie der Reihe nach mit den entsprechenden Data-Pointern. In der ersten Struktur gibst du die Anzahl an Loops an und als Flag nur WHAD_BeginLoop. Dann schreibst du diesen ersten Block und alle anderen Blöcke an die Sounddevice. Im letzten Block setzt du nur das Flag WHDR_EndLoop (keine Anzahl an Loops angeben, nur beimersten) und dann spielt er alles zwischen BeginLoop und EndLoop in einer Schleife ab.
Ob dir das jetzt geholfen hat, weiß ich nicht, aber so kannst du mehrere 5ms-Blöcke alle zusammen loopen, und ich hoffe, das war dien Problem. Wie es bei geloopten Blöcken mit der WOM_Done-Message aussieht, weiß ich leider nicht (also ob der Block sofort freigegeben wird, oder erst wenn er vollkommen fertig geloopt ist).
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Fr 21.03.03 22:58
Hab's ausprobiert, aber das Problem: die Sequenz soll so aussehen:
Chunk1-Chunk2-Chunk3-Chunk1-Chunk2-Chunk3-Chunk1...
also mache ich das:
Chunk1 = WHDR_BEGINLOOP
Chunk3 = WHDR_ENDLOOP
Welchem Chunk muss ich aber welchen Loop-Wert zuweisen? Bisher hatte ich nur einen Chunk, der hatte sowohl WHDR_BEGINLOOP als auch WHDR_ENDLOOP und $FFFFFFFF loops, also praktisch endlos. Aber wie mache ich das bei mehreren Chunks? In der SDK steht, das nur mit einem Chunk.
PS: Chunk sind die Daten, OK. Aber was ist ein RIFF?
_________________ Life is a bad adventure, but the graphic is really good!
|
|
OregonGhost
      
Beiträge: 215
|
Verfasst: Sa 22.03.03 12:02
RIFF = Resource Interchange File Format
Siehe dazu "Resource Interchange File Format Services" im PSDK, da werden die meisten Bezeichner erwähnt.
_________________ Oregon Ghost
---
Wenn NULL besonders groß ist, ist es fast schon wie ein bisschen eins.
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Sa 22.03.03 12:46
Ein RIFF ist wieder was anderes. Steht für Ressource Interchange File Format und ist ein chunk.-orientiertes Dateiformat. Damit werden zum Beispiel reine Wave-Dateien (auch PCM-komprimierte) oder Filme gepsiechert. Ist also nur ein Dateiformat, dürfte also uninteressant für dich sein, wenn du die Sinusfunktion nicht aus einer Datei auslesen willst oder in eine schreiben willst (näheres zum lesen siehe mein Tutorial in der entsprechenden Sparte, schreiben geht aber analog). Im SDK wird übrigens zwischen RIFF-Chunks und Audio Data Blocks (das ist das, was du hast, also pData in den WAVEHDR-Strukturen) unterschieden.
Den Loop-Wert ($FFFFFF) musst du nur dem ersten Block übergeben. Du hast also 3 Blöcke (nur die Bezeichnung Chunk ist falsch). Dann musst du Block1.dwLoops := $FFFFF schreiben, mehr nicht. Alle anderen Blöcke (2 - n) dürfen keine Loop-Angabe erhalten.
Ist jetzt aber nicht ausprobiert, so steht's nur im SDK (Referenzseite für WAVEHDR-Structure).
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Sa 22.03.03 12:57
Hä? Sowohl in der Delphi-Dku als auch auf MSDN habe ich nix darüber gefunden.
Egal, ich hab's probiert, Fehlanzeige! also:
1) WHDR_BEGINLOOP, Loops=$FFFFFFFF
2) 0, Loops=0
3) 0, Loops=0
1) WHDR_ENDLOOP, Loops=0
Jetzt kommt der 1. Block, die anderen werden nur für ein paar ms angestimmt. Waum?
_________________ Life is a bad adventure, but the graphic is really good!
|
|
tommie-lie
      
Beiträge: 4373
Ubuntu 7.10 "Gutsy Gibbon"
|
Verfasst: Sa 22.03.03 14:46
komisch...
Zeig mal den Code dafür, vielleicht ist da die Lösung drin (die Prozedur in der du die Blöcke vorbereitest und schreibst dürfte reichen, dnke ich).
Und stehen tut das alles im PSDK. Die Delphi-Hilfe ist eh nicht für die API gedacht, daher steht da sowas nicht drin.
| PSDK, Kapitel Multimedia hat folgendes geschrieben: | | Use the dwLoops member in the WAVEHDR structure for the first block in the loop to specify the number of times to play the loop. |
Eigentlich müsste es also reichen, nur den ersten Block die Anzahl an Loops zu übergeben. Probier es mal aus, in allen Blöcken die Loops anzugeben und auch mal im ersten und letzten (also in denen mit den beiden Flags).
_________________ Your computer is designed to become slower and more unreliable over time, so you have to upgrade. But if you'd like some false hope, I can tell you how to defragment your disk. - Dilbert
|
|
Andreas Pfau 
      
Beiträge: 997
|
Verfasst: Sa 22.03.03 18:57
Hoffnungslos! Hier mein Code:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| procedure TMain.Button3Click(Sender: TObject); const Frequency = 600.0; var Id: HWaveOut; Fmt: TWaveFormatEx; Hdr: Array[0..3] Of TWaveHdr; Buf: Array[0..3] Of Pointer; Siz, Sam, Byt, Sps: Integer; I, J: Integer; begin Sps := 96000; Byt := 2; Sam := Sps div 2;
Fmt.cbSize := SizeOf(Fmt); Fmt.wFormatTag := Wave_Format_Pcm; Fmt.nChannels := 1; Fmt.nSamplesPerSec := Sps; Fmt.nAvgBytesPerSec := Sps * Byt * 1; Fmt.nBlockAlign := Byt * 1; Fmt.wBitsPerSample := Byt * 8;
If WaveOutOpen(@Id, Wave_Mapper, @Fmt, 0, 0, 0) = MmSysErr_NoError Then begin Siz := SizeOf(SmallInt) * Sam;
For I := 0 To 3 Do begin GetMem(Buf[I], Siz); ZeroMemory(@Hdr[I], SizeOf(Hdr[I])); end;
For I := 0 To Sam - 1 Do PSmallInt(Integer(Buf[0]) + I * SizeOf(SmallInt))^ := Round(Sin((I / (Sam / 100)) * 2 * Pi) * $7fff); For I := 0 To Sam - 1 Do PSmallInt(Integer(Buf[1]) + I * SizeOf(SmallInt))^ := IfThen(Sin((I / (Sam / 100)) * 2 * Pi) > 0, $7fff, -$7fff); For I := 0 To Sam - 1 Do PSmallInt(Integer(Buf[2]) + I * SizeOf(SmallInt))^ := Round(Sin((I / (Sam / 100)) * 2 * Pi) * $7fff); For I := 0 To Sam - 1 Do PSmallInt(Integer(Buf[3]) + I * SizeOf(SmallInt))^ := IfThen(Sin((I / (Sam / 100)) * 2 * Pi) > 0, $7fff, -$7fff);
For I := 0 To 3 Do begin Hdr[I].lpData := PChar(Buf[I]); Hdr[I].dwBufferLength := Siz; end; Hdr[0].dwLoops := $FFFFFFFF; Hdr[0].dwFlags := Whdr_BeginLoop; Hdr[3].dwFlags := Whdr_EndLoop;
For I := 0 To 3 Do WaveOutPrepareHeader(Id, @Hdr[I], SizeOf(Hdr[I])); For I := 0 To 3 Do WaveOutWrite(Id, @Hdr[I], SizeOf(Hdr[I]));
Sleep(3000); WaveOutBreakLoop(Id); WaveOutReset(Id); For I := 0 To 3 Do WaveOutUnprepareHeader(Id, @Hdr[I], SizeOf(Hdr[I])); WaveOutClose(Id); For I := 0 To 3 Do FreeMem(Buf[I]); end Else ShowMessage('Das Gerät konnte nicht geöffnet werden'); end; |
Ich erstelle folgende Blöcke:
1-Sinus 2-Rechteck 3-Sinus 4-Rechteck
alle Blöcke sind ein paar ms lang und sollen in dieser Reihenfolge zusammengesetzt eine endlosschleife (also $FFFFFFFF loops) ergeben.
Wie kann ich das abändern, dass es funzt?
_________________ Life is a bad adventure, but the graphic is really good!
|
|
|