Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   .NET-Framework (managed code) (https://www.delphipraxis.net/79-net-framework-managed-code/)
-   -   C# Delphi type nach c# (https://www.delphipraxis.net/182611-delphi-type-nach-c.html)

EWeiss 5. Nov 2014 07:53

Delphi type nach c#
 
Wie könnte ich das nach c# umsetzen ?

Delphi-Quellcode:
type
 TWaveData = array [0 .. 1023] of smallint;

 MeineClass = class(TComponent)
 public
   function GetWaveData: TWaveData;

end;
gruss

Neutral General 5. Nov 2014 08:29

AW: Delphi type nach c#
 
Was ich gefunden hab wäre oben bei den "uses":

Code:
using TWaveData = Int16[1024];
Aber das ist ungetestet. (Quelle: http://stackoverflow.com/questions/9...g-type-aliases )

Dejan Vu 5. Nov 2014 09:54

AW: Delphi type nach c#
 
Nee, das geht so nicht.

So wäre es straightforward.
Code:
class MyClass
{
  public int[] GetWaveData { return new int16[1024]; }
}
Wenn Du auf deinen 1024 Words bestehst, dann kannst Du das auch in eine Klasse packen und verhindern, das man den Puffer verändert;
Code:
class WaveData
{
  private readonly Int16[] data = new Int16[1024];
  public Int16[] Data {get{return data;}}
}
Dafür ein Unittest und fertig.
Code:
[Test]
public void WaveDataSizeTest()
{
  var unit = new WaveData();
  Assert.AreEqual(unit.Data.Length, 1024);
}
Alternativ geht es auch mit unsafe:
Code:
internal unsafe struct WaveData
{
    public fixed Int16 Data [1024];
}

internal class MeineClass
{
    public unsafe WaveData GetWaveData()
    {
        var myWaveData = new WaveData();
        myWaveData.Data[0] = 3;
        return myWaveData;
    }
}
Dann musst Du mit der Option '/unsafe' kompilieren bzw. dies so in den Projekteigenschaften einstellen.

Ich persönlich würde eine der ersten beiden Varianten wählen. Ich weiß nicht, ob die 1024 Words in Stein gemeißelt sein müssen. Imho reicht es, wenn 1024 Elemente geliefert werden und dann -wie es sein sollte- über 'Length' iteriert wird.

Es wäre aber natürlich denkbar, das an 1000 Stellen im Code implizit diese Größe vorausgesetzt wird, dann Variante #2.

Der Nachteil/Das Besondere von #3 ist der, das der Speicherbereich nicht mehr verändert wird, d.h. die Adresse ändert sich nicht mehr.

EWeiss 5. Nov 2014 16:55

AW: Delphi type nach c#
 
Danke.
Weis jetzt nicht ob das so möglich ist unter MSV

int16 ja da muss ich drauf bestehen denn anschließend benötige ich das gleiche nochmal
mit 32 Bit Floating Point also float[1024]

Ich wollte es so machen
Geht aber nicht.

Code:
namespace MediaPortal.UI.Presentation.Players
{
  /// <summary>
  /// Provides access to sound player functionality needed to render Wave.
  /// </summary>
  public interface IWavePlayer : IAudioPlayer
  {
    float WaveData = new WaveData[1023];
    int16 WaveData32 = new WaveData32[1023];

    //Hier ne function mit der ich den wert zurückgeben kann wie in Delphi halt
  }
}
0..1023 = 1024 in c# ?

gruss

Dejan Vu 5. Nov 2014 17:16

AW: Delphi type nach c#
 
Da fehlen noch die [] in der Deklaration. Egal was Du willst, es geht nur so, wie ich beschrieben habe. Such dir eins aus.
Und klar: 1024 Elemente belegen die Indizes 0 bis 1023 einschließlich. Also müsstest Du deine Arrays mit [1024] instantiieren.
Code:
namespace MediaPortal.UI.Presentation.Players
{
  public class WaveData
  { // siehe meinen Code
  }

  /// <summary>
  /// Provides access to sound player functionality needed to render Wave.
  /// </summary>
  public interface IWavePlayer : IAudioPlayer
  {
    int[] GetWaveData(); // so
    WaveData GetWaveData1(); // oder so
 }

}

EWeiss 5. Nov 2014 17:51

AW: Delphi type nach c#
 
Danke dir..
Bin jetzt etwas Durcheinander weil von einem Beitrag auf den anderen verwiesen wird.
Werd mal schauen ob ich das jetzt irgendwie zusammenkleben kann.

gruss

EWeiss 5. Nov 2014 19:17

AW: Delphi type nach c#
 
Komme noch nicht ganz zurecht.

Code:
namespace MediaPortal.UI.Presentation.Players
{
  /// <summary>
  /// Provides access to sound player functionality needed to render Wave over 32 Bit Floating Point. See BASS_SAMPLE_FLOAT.
  /// </summary>
  public class WaveData32
  {
    private readonly float[] data = new float[1024];
    public float[] Data { get { return data; } }
  }
 
  /// <summary>
  /// Provides access to sound player functionality needed to render Wave.
  /// </summary>
  public class WaveData
  {
    private readonly Int16[] data = new Int16[1024];
    public Int16[] Data { get { return data; } }
  } 

  /// <summary>
  /// Provides access to sound player functionality needed to render a spectrum analyzer.
  /// </summary>
  public interface IVizAnalyze : IAudioPlayer
  {
   
    WaveData GetWaveData();

    WaveData32 GetWaveData32();
  .....
Rückgabe: c#
Code:
    public WaveData GetWaveData()
    {
      BassStream vizStream = _controller.PlaybackProcessor.VizStream;
      if (vizStream == null)
        return GetWaveData(); // <- Fehler?

      if (_externalState == PlayerState.Active)
      {
        if (BassWasapi.BASS_WASAPI_IsStarted())
        {
          BassWasapi.BASS_WASAPI_GetData(return , 2048);
        }
        else
          Bass.BASS_ChannelGetData(vizStream.Handle, return, 2048);
      }
    }
Delphi wäre return @Result
also
TWaveData = array [0 .. 1023] of smallint;

wie muss ich das noch umsetzen?
Will irgendwie nicht.

gruss

Dejan Vu 5. Nov 2014 19:47

AW: Delphi type nach c#
 
100% habe ich den Code nicht verstanden, aber ich versuche es mal

Code:
public WaveData GetWaveData()
{
  WaveData result = new WaveData();
  BassStream vizStream = _controller.PlaybackProcessor.VizStream;
  if (vizStream == null)
     return result;

  if (_externalState == PlayerState.Active)
  {
    if (BassWasapi.BASS_WASAPI_IsStarted())
    {
      BassWasapi.BASS_WASAPI_GetData(WaveData.Data , 2048);
    }
    else
    {
      Bass.BASS_ChannelGetData(vizStream.Handle, WaveData.Data, 2048);
    }
  }
  return result;
}
Hier ist es wichtig, wie die DLL-Aufrufe in C# deklariert sind.

EWeiss 5. Nov 2014 20:23

AW: Delphi type nach c#
 
Zitat:

Zitat von Dejan Vu (Beitrag 1278836)
100% habe ich den Code nicht verstanden, aber ich versuche es mal

Code:
public WaveData GetWaveData()
{
  WaveData result = new WaveData();
  BassStream vizStream = _controller.PlaybackProcessor.VizStream;
  if (vizStream == null)
     return result;

  if (_externalState == PlayerState.Active)
  {
    if (BassWasapi.BASS_WASAPI_IsStarted())
    {
      BassWasapi.BASS_WASAPI_GetData(WaveData.Data , 2048);
    }
    else
    {
      Bass.BASS_ChannelGetData(vizStream.Handle, WaveData.Data, 2048);
    }
  }
  return result;
}
Hier ist es wichtig, wie die DLL-Aufrufe in C# deklariert sind.

Super.. ;) Danke schön
Jetzt nur noch ein kleines Problem..

Zitat:

Error 2 Argument 1: cannot convert from 'short[]' to 'float[]' D:\MP 2.0\MediaPortal-2\MediaPortal\Source\UI\Players\BassPlayer\BassPla yer.cs 445 42 BassPlayer
BASS_WASAPI_GetData erwartet als Argument float[] ich muss aber short übergeben

Delphi
Delphi-Quellcode:
  TWaveData  = array [0 .. 1023] of smallint; // Wave Data
  TWaveData32 = array [0 .. 1023] of Single;  // 32 Bit Wave Data
gruss

Medium 6. Nov 2014 00:26

AW: Delphi type nach c#
 
Dann wirst du wohl zwei Arrays brauchen, eins mit floats und eines mit int16. Das float-Array in GetData() einsetzen, dessen Inhalt danach unter dem üblichen Genauigkeitsverlust in das int16-Array umkopieren (bzw. "umkopikonvertieren"), und dieses dann nachher weiter benutzen. Anders würde man das in Delphi auch nicht machen können, wenn schlicht die Typen (und in diesem Fall sogar die Längen in Byte) nicht übereinstimmen.

Am Rande: Ich vermute, dass Wave-Daten als Floats in Werten von -1..1 geliefert, als int16 aber -32768..32767 erwartet werden. Du müsstest in diesem Fall dann natürlich entsprechend skalieren beim "umkopikonvertieren".

EWeiss 6. Nov 2014 05:16

AW: Delphi type nach c#
 
Zitat:

Anders würde man das in Delphi auch nicht machen können.
In Delphi mache ich folgendes.

Delphi-Quellcode:
function TBASSBoxVis.GetWaveData: TWaveData;
begin
  // Get Wave data from stream
  if Basswasapi_Loaded and USE_WASAPI then
    BASS_WASAPI_GetData(@Result, 1024)
  else
  Bass_ChannelGetdata(BB_VisRenderThread.Stream, @Result, 1024);

end;

function TBASSBoxVis.GetWaveData32: TWaveData32;
begin
  // Get Wave data from 32 Bit stream
  if Basswasapi_Loaded and USE_WASAPI then
    BASS_WASAPI_GetData(@Result, 4096)
  else
  Bass_ChannelGetdata(BB_VisRenderThread.Stream, @Result, 4096);

end;
Wird wie folgt ausgeführt
Delphi-Quellcode:
    if (ChanInfo.flags and BASS_SAMPLE_FLOAT) = BASS_SAMPLE_FLOAT then
    begin
      FWaveData32 := GetWaveData32;
      for i := 0 to 1023 do
        if FWaveData32[i] > 0 then
          FWaveData[i] := round(Min(FWaveData32[i] * 32768, 32767))
        else
        FWaveData[i] := round(Max(FWaveData32[i] * 32768, -32768));
    end else
    FWaveData := GetWaveData;

    RenderOpenGL(@FWaveData, @FFFTData, BB_VisRenderThread.StreamPos);
Dort nehme ich einen pointer was ohne Probleme funktioniert.

Delphi-Quellcode:
function TBASSBoxVis.RenderOpenGL(WaveData, FFT: Pointer;
  MediaPos: Dword): BOOL;
Für wasapi gibt es eine Überladung..
Code:
public extern static int BASS_WASAPI_GetData(IntPtr buffer, int length);
Auch für die andere Funktion könnte ich einen Pointer verwenden
Code:
public extern static int BASS_ChannelGetData(int handle, IntPtr buffer, int length);
Dann wäre ich von der API her der von Delphi schon mal gleich.
Jetzt wäre dann nur noch zu klären was übergebe ich als Pointer.

In Delphi wäre das der Pointer auf TWaveData
In c# mag er das aber nicht wenn ich den Pointer auf die Class WaveData zurück gebe.
Zitat:

Error 1 'MediaPortal.UI.Presentation.Players.WaveData32' is a 'type' but is used like a 'variable' D:\MP 2.0\MediaPortal-2\MediaPortal\Source\UI\Players\BassPlayer\BassPla yer.cs 449 63 BassPlayer

Irgendwie hab ich in C# da kleine Probleme.. kann nur besser werden

gruss

Dejan Vu 6. Nov 2014 07:07

AW: Delphi type nach c#
 
Zeiger sind in C# verpönt, aber wenn es doch mal sein muss:
Code:
        public WaveData GetWaveData()
        {
            WaveData result = new WaveData();
            BassStream vizStream = _controller.PlaybackProcessor.VizStream;
            if (vizStream == null)
                return result;
            fixed(Int16* p = result.Data)
            {
                IntPtr ptr = (IntPtr)p;
                if (_externalState != PlayerState.Active)
                    return result;
               
                if (BassWasapi.BASS_WASAPI_IsStarted())
                {
                    BassWasapi.BASS_WASAPI_GetData(ptr, 2048);
                }
                else
                {
                    Bass.BASS_ChannelGetData(vizStream.Handle, ptr, 2048);
                }
                return result;
            }
        }
Ist aber ungetestet und ich habe das so noch nicht gemacht.

EWeiss 6. Nov 2014 07:50

AW: Delphi type nach c#
 
Danke..

Habe es jetzt so gemacht
Code:
    unsafe
    public WaveData32 GetWaveData32()
    {
      WaveData32 result = new WaveData32();
      BassStream vizStream = _controller.PlaybackProcessor.VizStream;
      if (vizStream == null)
        return result;

      fixed (float* p = WaveData32.Data32)
      {
        IntPtr ptr = (IntPtr)p;
        if (_externalState == PlayerState.Active)
        {
          if (BassWasapi.BASS_WASAPI_IsStarted())
          {
            BassWasapi.BASS_WASAPI_GetData(ptr, 2048);
          }
          else
          {
            Bass.BASS_ChannelGetData(vizStream.Handle, ptr, 2048);
          }
        }
        return result;
      }
    }

    unsafe
    public WaveData GetWaveData()
    {
      WaveData result = new WaveData();
      BassStream vizStream = _controller.PlaybackProcessor.VizStream;
      if (vizStream == null)
        return result;

      fixed (Int16* p = WaveData.Data16)
      {
        IntPtr ptr = (IntPtr)p;
        if (_externalState != PlayerState.Active)
          return result;

        if (BassWasapi.BASS_WASAPI_IsStarted())
        {
          BassWasapi.BASS_WASAPI_GetData(ptr, 2048);
        }
        else
        {
          Bass.BASS_ChannelGetData(vizStream.Handle, ptr, 2048);
        }
        return result;
      }
    }

wobei sich das
Code:
fixed(Int16* p = result.Data)
nicht kompilieren lässt.

Nochmal extra :thumb: für deine Hilfe

gruss

Dejan Vu 6. Nov 2014 08:10

AW: Delphi type nach c#
 
Wenn er wegen 'unsafe Code' meckert, dann musst du in den Compilereinstellungen was drehen (Eigenschaften des Projekts "Unsicheren Code zulassen"). Dann sollte es gehen. Auch wenn es nervt: Es ist gut, das man solche unsicheren Stellen (Buffer Overrun) im Code explizit markieren muss und sogar dem ganzen Projekt das Attribut "Ich bin unsicher" verpasst.

EWeiss 6. Nov 2014 09:04

AW: Delphi type nach c#
 
Zitat:

Zitat von Dejan Vu (Beitrag 1278872)
Wenn er wegen 'unsafe Code' meckert, dann musst du in den Compilereinstellungen was drehen (Eigenschaften des Projekts "Unsicheren Code zulassen"). Dann sollte es gehen. Auch wenn es nervt: Es ist gut, das man solche unsicheren Stellen (Buffer Overrun) im Code explizit markieren muss und sogar dem ganzen Projekt das Attribut "Ich bin unsicher" verpasst.

Das habe ich gemacht unter build Option

Zitat:

"Ich bin unsicher" verpasst.
Ist aber Fies
Ein Code muss nicht schlecht sein weil ich ihm einen Pointer verpasse

Danke.

Dejan Vu 6. Nov 2014 10:26

AW: Delphi type nach c#
 
Nein.
Unsicher != Schlecht.
Unsicher = Unsicher.

Wenn ich aber in meiner (z.B.Web)anwendung eine unsafe DLL entdecke, dann weiß ich, das ich hier ein potentielles Sicherheitsrisiko habe, was ich genauer unter die Lupe nehmen muss...

Medium 6. Nov 2014 10:44

AW: Delphi type nach c#
 
Es birgt inhärent Gefahrenquellen, die das Konzept hinter C# eigentlich komplett zu eliminieren sucht. Das ist sogar einer der Design-Basen. Insofern ist es, in der .NET-Welt, durchaus als "schlecht" anzusehen. Ich stolpere aber selbst oft genug über Dinge, wo es anders nicht oder nur mit gewaltigen Performanceeinbußen "richtig" ginge - gerade bei der Nutzung von nicht-.NET Libs - um zu wissen, dass die Praxis einfach noch immer anders spielt als die Theorie idealisiert. Von daher: Gräme dich nicht. Ein Purist würde sicher seine Nase rümpfen, Pragmatiker sehen das anders. Und wer mag schon Puristen :)
Sauber programmiert ist das alles ja auch okay. Die "unsafe" Marker sollen einen im Prinzip nur daran erinnern, dass hier jetzt bitte wirklich echte große Sorgfalt herrschen soll.
(Ich würde nur nicht anfangen auf diese Weise Dinge zu erledigen, für die C# bzw. .NET ins Framework passende Wege bereit stellt. Man könnte in C# ja durchaus dynamische Arrays genau so wie unter C machen, aber da würde ich dann auch den großen Hammer raus holen und ein bischen auf dem Entwickler damit rumklopfen =))

EWeiss 6. Nov 2014 14:25

AW: Delphi type nach c#
 
Na dann ;)
In dem Fall bin ich beruhigt.

gruss


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:22 Uhr.

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