Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Dynamische Arrays ... kleines Problem! (https://www.delphipraxis.net/74376-dynamische-arrays-kleines-problem.html)

sonicfire 3. Aug 2006 20:55

Re: Dynamische Arrays ... kleines Problem!
 
Zitat:

Zitat von Der_Unwissende
Zitat:

Zitat von sonicfire
Delphi-Quellcode:
Procedure TForm1.LoadTheWave(FileName: String; out Value: TSmallIntArray;Start: Integer = 0);
begin
  with TFilestream.Create(Filename, fmOpenRead) do
    try
      Position := Size;
      setlength(Value, Size-Position);
      ReadBuffer(Value,length(Value));
    finally
      Free;
    end;
end;

Schau dir mal an was du hier tust! Du setzt Position := Size und dann die Länge von Value auf Size - Position, anders gesagt, du setzt die Länge von Value auf 0.
Wenn du 0 Byte zu schreiben hast, nun ja, dann wird natürlich auch nie irgendwas geschrieben...

Gruß Der Unwissende

Okay, leuchtet ein ... aber warum bekomme ich Stream-Errors wenn ich Position einfach weglasse? Oder Position := 0 (was logisch wäre)? ... genauso - müsste setlength(Value, Size) nicht funktionieren? (Aber nein, tut es nicht)...ARGH! Ich könnte echt nur auskeksen....seufz :)

DGL-luke 3. Aug 2006 21:07

Re: Dynamische Arrays ... kleines Problem!
 
@Der_Unwissende:

Macht man das nicht seit neuestem so:

Delphi-Quellcode:
TFileStream.Create(FileName, fmOpenRead, fmShareExclusive); //man beachte das Komma
@sonicfire: Du hast den falschen Code von mir kopiert :gruebel: - NEIN verdammt, ich habe den falschen geschrieben! Sorry! das sollte position := Start heissen!

sonicfire 3. Aug 2006 21:11

Re: Dynamische Arrays ... kleines Problem!
 
Danke, Luke!

Quasi so:?
Delphi-Quellcode:
Procedure TForm1.LoadTheWave(FileName: String; out Value: TSmallIntArray; Start: Integer = 0);
begin
  with TFilestream.Create(Filename, fmOpenRead) do
    try
      Position := Start;
      setlength(Value, Size-Position);
      ReadBuffer(Value,length(Value));
    finally
      Free;
    end;
end;
Aber das gibt wieder einen Stream- RuntimeError! :wiejetzt: :gruebel:

DGL-luke 3. Aug 2006 21:22

Re: Dynamische Arrays ... kleines Problem!
 
Hmm... eventuell kommst du über den rand hinaus mit dem readbuffer... versuchs mal mit read ohne buffer, evtl. hilft das was.

ich muss mal überlegen... angenommen, wir haben einen header, der 5 bytes lang ist. dann wird als start 6 übergeben, und position = 6.

Angenommen Größe 10, wird ...aaaahhh.... :coder2:

weiter im text. größe der datei 10, dann haben wir noch 4 bytes zu lesen. also setzen wir die größe des arrays - natürlcih - auf 4 bytes geteilt durch (!) größe unseres datentyps. das ham wir (hab ich) hier schon mal falsch gemacht. also, angenommen

Delphi-Quellcode:
Procedure TForm1.LoadTheWave(FileName: String; out Value: TSmallIntArray; Start: Integer = 0);
begin
  with TFilestream.Create(Filename, fmOpenRead) do
    try
      Position := Start;
      setlength(Value, (Size-Position) div sizeof(SmallInt));
      ReadBuffer(Value,length(Value));
    finally
      Free;
    end;
end;

wenn ein smallint 2 byte groß ist (hypothetisch), ist value jetzt 4 / 2 = 2 Smallints groß. Also haben wir vier bytes zu lesen und müssen im readbuffer die Länge wieder auf 4 bringen - also wieder *sizeof(SmallInt):

Delphi-Quellcode:
Procedure TForm1.LoadTheWave(FileName: String; out Value: TSmallIntArray; Start: Integer = 0);
begin
  with TFilestream.Create(Filename, fmOpenRead) do
    try
      Position := Start;
      setlength(Value, (Size-Position) div sizeof(SmallInt));
      ReadBuffer(Value,length(Value) * sizeof(SmallInt));
    finally
      Free;
    end;
end;
Das hat uns aber noch nicht weitergebracht als bis dahin, dass das Ergebnis nicht mehr viel zu groß ist - sollte also die Fehler nicht nicht beheben.

EDIT: Wo genau tritt denn der runtime-error auf? Du kannst im Quelltext breakpoints setzen, indem du im editor links neben die zeile klickst (im grauen), wenn der programmcode da vorbeikommt, hält der debugger die ausführung an. damit kannst du genau sehen, wanns knallt.

sonicfire 3. Aug 2006 21:30

Re: Dynamische Arrays ... kleines Problem!
 
So wie es aussieht crasht es bei
Delphi-Quellcode:
ReadBuffer(Value,length(Value) * sizeof(SmallInt));

DGL-luke 3. Aug 2006 21:33

Re: Dynamische Arrays ... kleines Problem!
 
Ok, benutze einfach mal Read anstelle von ReadBuffer. :)

sonicfire 3. Aug 2006 21:36

Re: Dynamische Arrays ... kleines Problem!
 
Jepp, das funzt soweit .. :)
Nur zerstört er dann am Ende das WAV-File ...hmm...

EDIT: Achso! Muss ja noch das Offset für den Header setzen!

sonicfire 3. Aug 2006 21:38

Re: Dynamische Arrays ... kleines Problem!
 
seufz... jetzt sind im Audio-Teil des WAV´s daten die da nicht hingehören *G* :coder2:

Genauso verwunderlich ist immernoch, das ich den Inhalt vom WavBuffer komplett auf 0 setze, das heisst es müsste totale Stille im WAV sein - aber da ist nichts verändert

DGL-luke 3. Aug 2006 21:56

Re: Dynamische Arrays ... kleines Problem!
 
Rufst du es auch mit Start = sizeof(Header)+1 auf? sonst liest du das letzte byte vom header noch mit aus.

Wo genau setzt du den Inhalt auf 0? Vielleicht irgendwo, wo danach gleich wieder drüber geschrieben wird bzw. in einer lokalen Variable, wo es gar keine Wirkung hat?

SaveToFileAppend() ist übrigens dafür gedacht, zuerst den header in die Datei zu schreiben und dann die Daten. Allerdings hat das einiges an Overhead, denn nachdem du den Header geschrieben hast, musst du erst mal die Datei schließen und sie dann (durch aufruf meiner funktion) wieder öffnen und beschreiben. Ist nicht optimal, du solltest beides in einem Aufwasch machen.

sonicfire 3. Aug 2006 21:59

Re: Dynamische Arrays ... kleines Problem!
 
Eigentlich schon! :)

Momentan versuche ich es so, aber werds jetzt mal innerhalb einer Prozedur versuchen!

Delphi-Quellcode:
Procedure TForm1.ProcessWave(FileName: String);
var
    Wavbuffer: TSmallIntArray;
    Header: TWaveHeader;
    i: Integer;

begin
  LoadTheWave(Outputfile.Text, Wavbuffer, sizeOf(Header)+1); // reine audio daten laden
  for i := Low(Wavbuffer) to High(Wavbuffer) do // testweise stille einfügen
  begin
//    Wavbuffer[i] := Wavbuffer[i];
    Wavbuffer[i] := 0;
  end;
  SaveTheWave(Outputfile.Text, Wavbuffer, sizeOf(Header)+1);
end;

Hawkeye219 3. Aug 2006 22:06

Re: Dynamische Arrays ... kleines Problem!
 
Hallo,

der Stream-Fehler wird wahrscheinlich verschwinden, wenn ihr den Arrayinhalt und nicht den Arrayzeiger (und die darauf folgenden Speicherinhalte) lest/schreibt:

Delphi-Quellcode:
:
ReadBuffer(Value[0], Length(Value) * SizeOf(SmallInt));
:
WriteBuffer(Value[0], Length(Value) * SizeOf(SmallInt));
:
Gruß Hawkeye

DGL-luke 3. Aug 2006 22:10

Re: Dynamische Arrays ... kleines Problem!
 
was ist denn savethewave? Ich kann mir im moment keine kombination meiner funktionen vorstellen, die da zufriedenstellende ergebnisse bringt. obwohl... im beitrag #38, wenn da noch das start und die position-zuweisung drinstehen, dann ist die transferleistung schon erbracht ;)

@Hawkeye219: ahh... das hatte ich zwischendurch schon mal so im hinterkopf... danke! aber ist das denn nicht identisch?!

sonicfire 3. Aug 2006 22:16

Re: Dynamische Arrays ... kleines Problem!
 
HawkEye: Ja tritts mich doch ein Pferd, stimmt - natürlich! Sonst schreibt er die Bytes bzw. Größe der Typ-Definition ins File, nicht aber die eigentlich Daten! Das war es! :) Vielen Dank! Und danke nochmal an DGL-Luke!!

Achso und: SaveTheWave z.b. ist nichts weiter als deine Original SaveToFile-Prozedure! ;) Mit den anderen Prozeduren genauso! :)

DGL-luke 3. Aug 2006 22:21

Re: Dynamische Arrays ... kleines Problem!
 
schön, dass es funktioniert... Ähm.. das kann aber nicht sein...

Delphi-Quellcode:
SaveTheWave(Outputfile.Text, Wavbuffer, sizeOf(Header)+1);
Weder meine SaveToFile noch meine SaveToFileAppend haben einen dritten parameter...

sonicfire 3. Aug 2006 22:37

Re: Dynamische Arrays ... kleines Problem!
 
Doch, klar? Ich übergeb damit den Start - Wert (?) :)

sonicfire 3. Aug 2006 23:02

Re: Dynamische Arrays ... kleines Problem!
 
Procedure TForm1.ProcessWave(FileName: String);
var
Wavbuffer: TSmallIntArray;
Header: TWaveHeader;
i: Integer;
Amp: Double;

begin
Amp := 0.5; // halbieren der lautstärke
LoadTheWave(Outputfile.Text, Wavbuffer, sizeOf(Header)+1); //laden der audio daten
for i := Low(Wavbuffer) to High(Wavbuffer) do
begin
Wavbuffer[i] := Floor(Wavbuffer[i]*Amp);
end;
SaveTheWave(Outputfile.Text, Wavbuffer, sizeOf(Header)+1);
end;

wav file result: beinahe weisses rauschen :gruebel: (ging mit meinem alten wurst-code)
Hat jemand eine Idee? :)

EDIT: Wenn ich z.b. bei Amp := 2 verwende, wird die Lautstärke korrekt verdoppelt? Merkwürzig. :(

Hawkeye219 3. Aug 2006 23:13

Re: Dynamische Arrays ... kleines Problem!
 
Da die Streamposition 0-basiert ist, muß der dritte Parameter bei Load/Save meiner Meinung nach so aussehen:

Delphi-Quellcode:
SizeOf(Header)
Gruß Hawkeye

sonicfire 3. Aug 2006 23:34

Re: Dynamische Arrays ... kleines Problem!
 
Ich glaub ich spinne! Vollkommen richtig! Jetzt versteh ich gar nichts mehr ... was hat ein Byte offset mit (hatte ja noch überall +1 drin) mit dem reinem "Klang-Ergebnis" zu tun?? Ich fass das alles nicht ... *G*
:stupid:

Hawkeye219 4. Aug 2006 08:01

Re: Dynamische Arrays ... kleines Problem!
 
In deinem Fall liegen die Samples als 16-Bit-Werte im Intel-Format (little endian) vor. Bei Stereo-Daten wechseln sich dabei die beiden Kanäle ab:

Code:
sample 0   sample 1   sample 2  sample 3    // sample
ch1  ch2   ch1  ch2   ch1  ch2  ch1  ch2    // Kanal (1=links, 2=rechts)
L H L H  L H L H  L H L H L H L H   // Byte (L=low, H=high)
Wenn du nun mit einer Verschiebung von 1 Byte auf die Daten zugreifst, kommt es gleich zu mehreren Fehlern:
  • die Byte-Reihenfolge im 16-Bit-Wort stimmt nicht mehr
  • linker und rechter Kanal werden vermischt
  • es findet ein sampleübergreifender Zugriff statt
Als Ergebnis erhältst du die dir bereits vertraute "Zufallsmusik".

Gruß Hawkeye

Der_Unwissende 4. Aug 2006 08:43

Re: Dynamische Arrays ... kleines Problem!
 
Zitat:

Zitat von sonicfire
Danke! Aber wieso ein "or" dazwischen? Nicht: fmOpenRead, fmSowieso?

Also, fmSowieso ist eigentlich nur eine Konstante Zahl. Diese hat aber eine besondere Eigenschaft, die du von den Delphi-Sets kennen kannst, ansonsten spricht man auch gerne von Bitfeldern. Wenn du ein Integer nimmst, hast du 32 Bit. Du kannst also theoretisch (auch praktisch) jedes einzelne Bit setzen oder eben nicht. Damit kannst du in einem Integer 32 Zustände speichern (die allerdings auch sehr einfach sind). Es ist halt wirklich ein Boolscher Wert (Bit = 1 oder nicht = 0).
Anschaulicher ist das ganze, wenn wir jetzt mal nur zwei Zustände z1 und z2 betrachten die auch nur in einem Byte kodiert werden (die anderen führenden 24 0en eines Integers lasse ich nur fauler Weise weg!).
In der binären Darstellung entspricht so eine Bit einer 2er Potenz. Das niederwertigste Bit entspricht 2^0 = 1, dass nächste 2^1 = 2, es kämen 2^2 = 4, 2^3 = 8, ...
Das n-te Bit ist also gerade 2^n (wobei man hier wieder sieht warum man so gerne mit der null beginnt).

Wenn du jetzt Zustände in Bits kodieren möchtest, solltest du ihnen jeweils ein eigenes Bit zuweisen (sonst kannst du schließlich die Zustände nicht unterscheiden). Dazu weißt du einfach der Konstanten eine 2er Potenz zu. Sagen wir in diesem Fall z1 = 1, z2 = 2 (was natürlich den beiden ersten Zweierpotenzen entspricht).
Hier gibt es 4 Möglichkeiten (Anzahl der Zustände ^ 2, da jedes Bit gesetzt sein kann oder nicht). Entweder ist z1 und z2 gesetzt oder nur z1 oder nur z2 oder keins.
Binär ist das 11, 01, 10, 00 (ok, denke dir einfach führende nullen für jeden größeren Datentyp!).

Der Zustand z1 ist dabei die Zahl 1, binär (hier mal als Byte) also 00000001
Der Zustand z2 ist dabei die Zahl 2, binär (hier mal als Byte) also 00000010

Wenn du mit Bits arbeitest, dann kannst du diese sehr leicht mit Bitmasken manipulieren. Und, Oder, Nicht, XOR, NOR, NAND, ... sind alles Verknüpfungen die du mit den Bits und einer Maske ausführen kannst. Wichtig sind in den meisten Fällen Und und Oder.
Schauen wir uns einfach mal die beiden an:
Und ist immer dann 1, wenn beide Bits 1 sind.
Oder ist immer dann 1, wenn mind. eins der Bits 1 ist.

Warum also hier oder?
00000010 oder
00000001
---------
00000011 // die Stellen sind eins, wo mindestens eine 1 stand!

Hier siehst du auch, warum die Konstanten nur 2er Potenzen sein dürften. Jede binäre Zahl setzt sich nur aus einer Summe von zweier Potenzen zusammen, alle anderen Werte würden mehr als ein Bit zur Kodierung benötigen (du könntest also weniger Zustände kodieren oder hättest Veränderungen von mehr als einem Zustand).
Ok, was im Ergebnis steht ist nichts anderes als die 3, also warum nicht addieren?
Den Unterschied merkst du immer dann, wenn du ein Bit setzen möchtest ohne den alten Zustand zu verlieren. Sagen wir du weißt gar nicht wie der alte Zustand aussieht, du möchtest aber unbedingt z2 setzen.
Bei der Addition würde folgendes passieren:
01000010 + // alter Zustand
01000010 // setzen von z2
---------
00000100 // 2 + 2 = 4, 4 <> z2 gesetzt!

Mit dem Oder:
01000010 oder // alter Zustand
00000010 // setzen von z2
---------
01000010 // da 1 wo mindestens eine 1 Stand, erwarteter Zustand!

Wie du hier siehst, wird der alte Zustand beim Oder bei behalten und es wird das neue Bit auf jeden Fall gesetzt. War es schon gesetzt, so ändert sich an diesem Bit nichts.

Wenn du nun im Programm wissen möchtest ob ein Zustand in so einer Variablen gesetzt ist, verwendest du die Eigenschaften einer speziellen Bitmaske und das logische Und. Und ist immer wahr, wenn beide Bits (die Verglichen werden) 1 sind. Wenn du also wissen willst ob ein Bit gesetzt ist, darf deine Maske nur an dieser Stelle 1 sein. Eine Und-Verknüpfung liefert dir dann einen Wert > 0 wenn das Bit gesetzt war. Prüfen wir am letzten Ergebnis ob z1 und z2 gesetzt sind:

Prüfen ob z1 gesetzt:
010000010 und // letztes Ergebnis
000000001 // Bitmaske für z1
----------
000000000 // nicht > 0, damit kein z1 gesetzt

Prüfen ob z2 gesetzt:
010000010 und // letztes Ergebnis
000000010 // Bitmaske für z2
----------
000000010 // > 0, damit z2 gesetzt


So, deswegen verwendet man dort einfach die Oder-Verknüpfung. Sie ist hier als logisches Oder (auf Bitebene) zu verstehen. Die könntest du häufiger finden (gerade wenn es näher in Richtung API geht). Es ist eine durchaus übliche Art und Weise einfache Zustände zu kodieren, gerade wenn du in die Mikroprozessor Programmierung gehst (wo man nicht immer Massen an Speicher hat und auch gar nicht möchte).

Zitat:

Zitat von DGL-luke
Macht man das nicht seit neuestem so:

Delphi-Quellcode:
TFileStream.Create(FileName, fmOpenRead, fmShareExclusive); //man beachte das Komma

Echt? Ab welcher Version ist dass denn erlaubt? Kenne ich noch gar nicht. Also wenn das klappt, klar, noch schöner.

Phoenix 4. Aug 2006 10:18

Re: Dynamische Arrays ... kleines Problem!
 
Zitat:

Zitat von sonicfire
Aber wie das so ist - prompt hat man ein neues :wink:

Zitat:

Zitat von sonicfire
Dummerweise gibts schon wieder ein neues Problem Wink Hachja....*seufz*

:warn: Dann mach doch bitte auch für jede neue Frage einen neuen Thread auf. Das ist hier so Usus.

Zudem: BITTE keinen Code als Bild posten. Es gibt Leute, die sind immer noch mit Modem hier unterwegs oder haben nur ISDN und freuen sich keineswegs über solche verlängerten Ladezeiten.

Und wenn es unbedingt ein Bild sein muss, dann hänge das Bild bitte in den Anhang des Beitrages und linke es nicht direkt rein. Dann können es sich auch nur die Leute angucken, die es sehen wollen und es werden nicht zwangsläufig alle damit konfrontiert.

sonicfire 4. Aug 2006 15:45

Re: Dynamische Arrays ... kleines Problem!
 
Okay, werde mich daran halten! :oops: (Will nur nich dauernd neue Threads eröffnen).
Und das JPG-Bild ist kleeein ;)

@Hawkeye: Danke für die Info! :)
@Der Unwissende: Wow! :shock: Danke für die ausführliche Eklärung, muss mir das nochmal in Ruhe zu Gemüte führen! :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:14 Uhr.
Seite 2 von 2     12   

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz