ZVEI Tongenerator erstellen

  • VB.NET

Es gibt 74 Antworten in diesem Thema. Der letzte Beitrag () ist von mcbo.

    Falls es dich noch interessiert:
    Die PCMSoundStream-Klasse stellt einen Stream bereit, der beim Aufruf der Stream.Read-Funktion die Töne in einen Puffer einliest. Hierbei wird das Wave-Dateien zugrunde liegende Konzept aufgegriffen. In Wave-Dateien sind lediglich die Elongationen aneinandergereiht. Der Puffer wird bei mir über einen Delegaten gefüttert, damit wenigstens etwas Dynamik im Stream herrscht. Das Kernstück des Programms ist eigentlich genau dieser Stream.
    Wave-Dateien bestehen aus einem Header und Chunks (Brocken). Der Header stellt nur Informationen über die Wave-Datei selber zur Verfügung: Dass es sich um eine RIFF-Datei handelt, wie lang sie ist und dass es speziell eine Wave-Datei ist. Die vom PCMSoundStream erzeugte Wave-Datei liest den Header aus einem Array ein, das im Konstruktor erzeugt wird. Die Informationen werden über die WaveFormat-Struktur bereitgestellt, die Dauer und der der Berechnung zugrunde liegende Delegat werden ebenfalls übergeben:

    VB.NET-Quellcode

    1. Public Sub New(ByVal format As WaveFormat, ByVal duration As TimeSpan, ByVal computionHandler As ComputeValue)


    Der Delegat bei mir erzeugt Sinus-Wellen, also quasi "harmonische Wellen". Er wird in der ApplicationEssentials-Klasse definiert:

    VB.NET-Quellcode

    1. Private Shared Sub SineHandler(ByVal buffer() As Byte, ByVal offset As Integer, ByVal format As WaveFormat, ByVal blockOffset As Integer)
    2. 'channels = 1 ==> t = blockOffset / format.SamplesPerSecond
    3. Array.Copy(BitConverter.GetBytes(CShort(Short.MaxValue * Math.Sin(blockOffset / format.SamplesPerSecond * Math.PI * 440.0#))), 0, buffer, offset, 2)
    4. End Sub

    Wie man erkennt, wird die Berechnung auf Basis des Formates und der Position im Stream vorgenommen (vgl. blockOffset und PCMSoundStream.Read). Da mein Test nur mono ist, brauche ich auch nur eine Berechnung auszuführen. Die Berechnung hängt halt von der Frequenz ab, die bei mir 440 Hz ist (also 440.0#). Die Größe eines Samples ist bei mir 16, woraus auch eine Amplitude von Short.MaxValue hergeleitet wird (nach unten hin ist halt leider noch 1 Wert Platz, aber das war mir jetzt egal). Der Rest steht ja da: die vergangene Zeit t = blockOffset / format.SamplesPerSecond. Das ist jetzt aber genau auf diesen einen Fall zugeschneidert, da bei mir die Kanäle nicht berücksichtigt werden (sonst müsste man t = blockOffset / (format.SamplesPerSecond * format.BlockAlign) oder so nehmen). Der Rest ist wahrscheinlich selbsterklärend.

    Jetzt noch zum Konstruktor von PCMSoundStream und PCMSoundStream.Read:

    VB.NET-Quellcode

    1. Public Sub New(ByVal format As WaveFormat, ByVal duration As TimeSpan, ByVal computionHandler As ComputeValue)
    2. btHeader = New Byte(43) {}
    3. wfFormat = format
    4. intLength = CInt((format.AverageBytesPerSecond * duration.Ticks) \ TimeSpan.TicksPerSecond)
    5. Array.Copy(BitConverter.GetBytes(1179011410), btHeader, 4) 'RIFF
    6. Array.Copy(BitConverter.GetBytes(intLength), 0, btHeader, 4, 4)
    7. Array.Copy(BitConverter.GetBytes(1163280727), 0, btHeader, 8, 4) 'WAVE
    8. Array.Copy(BitConverter.GetBytes(544501094), 0, btHeader, 12, 4) 'fmt
    9. Array.Copy(BitConverter.GetBytes(16), 0, btHeader, 16, 4)
    10. Array.Copy(BitConverter.GetBytes(CShort(format.FormatTag)), 0, btHeader, 20, 2)
    11. Array.Copy(BitConverter.GetBytes(format.Channels), 0, btHeader, 22, 2)
    12. Array.Copy(BitConverter.GetBytes(format.SamplesPerSecond), 0, btHeader, 24, 4)
    13. Array.Copy(BitConverter.GetBytes(format.AverageBytesPerSecond), 0, btHeader, 28, 4)
    14. Array.Copy(BitConverter.GetBytes(format.BlockAlign), 0, btHeader, 32, 2)
    15. Array.Copy(BitConverter.GetBytes(format.BitsPerSample), 0, btHeader, 34, 2)
    16. Array.Copy(BitConverter.GetBytes(1635017060), 0, btHeader, 36, 4) 'data
    17. Array.Copy(BitConverter.GetBytes(intLength - 36), 0, btHeader, 40, 4)
    18. cvCompution = computionHandler
    19. End Sub

    Da wir kein unsafe in VB haben und ich aus Faulheit nicht über Marshalling arbeiten wollte, habe ich einfach Array.Copy und BitConverter.GetBytes verwendet. BitConverter.GetBytes gibt die Bytes von primitiven Datentypen zurück. Diese werden dann in das Array kopiert, das den Header der vereinfachten Datei bereitstellt. PCM-Wave-Dateien enthalten ganzzahlige Werte, wie SByte oder Int16 (Short).
    Jetzt noch die Read-Funktion mit Kommentaren:

    VB.NET-Quellcode

    1. Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer
    2. Read = Math.Min(count, intLength - intOffset)'... ermitteln wir die Anzahl der insgesamt ausgelesenen Bytes
    3. If intOffset < 44 Then 'werden Informationen aus dem Header benoetigt
    4. Dim hcount As Integer = Math.Min(44 - intOffset, count) 'enthaelt hcount die Anzahl der vom Header gelesenen Bytes
    5. Array.Copy(btHeader, intOffset, buffer, offset, hcount) 'der Headerinhalt wird kopiert
    6. If count > hcount Then 'ist die Anzahl der zu lesenden Bytes groesser, als der gelesene Header-Inhalt...
    7. count -= hcount '...wird die verbleibende Anzahl der Bytes wird berechnet
    8. For i As Integer = hcount To Read - 1 Step wfFormat.BlockAlign 'und die Werte werden eingelesen
    9. 'BlockAlign gibt uebrigens die Groesse eines Blocks ab (also Anz. der Kanaele * Sample-Groesse)
    10. cvCompution(buffer, offset + i, wfFormat, intOffset + i)
    11. Next
    12. End If
    13. Else
    14. 'sind keine Header-Informationen notwendig, werden die Werte einfach berechnet:
    15. For i As Integer = 0 To Read - 1 Step wfFormat.BlockAlign
    16. 'BlockAlign gibt uebrigens die Groesse eines Blocks ab (also Anz. der Kanaele * Sample-Groesse)
    17. cvCompution(buffer, offset + i, wfFormat, intOffset + i)
    18. Next
    19. End If
    20. intOffset += Read
    21. End Function

    Da war ich wohl nicht ganz fit, als ich den Code geschrieben hab... Die äußere If-Abfrage sollte weg und count -= hcount sollte innen stehen. Außerdem wird nicht um count erhöht, sondern um Read.. Entschuldigung für all die Fehler, das sollte nicht passieren...

    Der restliche Inhalt des PCMSoundStreams ist dazu da, den Stream zu vollenden.

    Gruß
    ~blaze~
    Hallo,

    interessiern tut es mich schon, nur wie gesagt, ist mir dieses Projekt anscheinend viel zu hoch um auch nur etwas davon begreifen zu können und selber weiter zu machen. Somit kann ich mit dem Code auch nichts anfangen. Den Code in deinem Beispiel hab ich mir durchgelesen, nur ich konnte absolut keine Stelle bzw. Begriffe drin finden, die ich schon mal selber benutzt habe!

    Also alles in allem habe ich KEINE Ahnung und kann damit nichts anfangen... Sorry

    Aber trotzdem danke für deine Mühen!!
    Gruss Chris
    So Chris, hier Dein Projekt (HP radio neu.zip)
    HP radio neu.zip

    Tut mir leid, dass es so lang gedauert hat, aber Besuch war wichtig!!!

    Die ausführbare Datei ist jetzt im hier:
    ...\HP radio neu\HP radio neu\bin\x86\Release\HP radio neu.exe
    Habe also von Any-CPU auf x86 umgestellt, läuft trotzdem auf beiden Architekturen. Ist wegen der bass.dll, kann ich dir später mal erklären.

    Sirenenprogramme und Sondertöne habe ich erstmal ausser acht gelassen, da ich noch nicht weiß, was du genau damit vor hast.
    Du gibst also deinen 5-stelligen Ziffern-Code ein und drückst "Auslösen". Vorher noch Tonfolge-Wiederholung auswählen,
    und ab geht der Peter.
    Sag mir bescheid, ob's funzt und was du noch benötigst.

    mfg OnkelR
    Hallo, kein Problem ich richte mich nach dir!!

    Habs ausprobiert und es funktioniert! Was mir dabei aufgefallen ist, wenn man aus versehen weniger als 5 Töne eingibt, geht das Programm flöten! Was mir noch aufgefallen ist, die fertige Tonfolge kommt mir irgendwie ein wenig zu langsam vor, hab das Programm noch mal gestartet und am Anfang gehts wieder gleich schnell, nur bei öfterem Auslösen, wird die Tonfolge irgendwie langsamer, oder täuscht das ??


    Sonst ist es in völlig Ordnung !

    Die Sirenenprogramme benötige ich in Zukunft für Tests von Fernwirkempfängern, wenn ich mal weiss, oder gesehen habe, wie man ein Programm anlegt, dann kann ich mir die restlichen dann wahrsch. eh selber machen, vorausgesetzt ich kappiere irgendwann den Code! Die Sondertöne sind auch meistens bei Fernwirkempfänger zu finden!

    Danke erstmal für deine Mühe!!
    Gruss Chris
    wenn man aus versehen weniger als 5 Töne eingibt,


    Habs vorhin auch gemerkt.

    ersetz das mal hiermit, dann gehts.
    Die boolean-Variable brauchst Du dann nicht mehr.

    VB.NET-Quellcode

    1. Private Sub Button25_Click....
    2. tbx_Status.Text = ""
    3. Button25.Visible = False
    4. Dim s As String = TextBox1.Text
    5. If s.Length <> 5 Then
    6. tbx_Status.Text = " Eingabe fehlerhaft"
    7. Button25.Visible = True
    8. Exit Sub
    9. End If
    10. Dim chk_string As String = s(0) & s(1) & s(2) & s(3) & s(4)
    11. If IsNumeric(chk_string) = False Then
    12. tbx_Status.Text = " Eingabe fehlerhaft"
    13. Button25.Visible = True
    14. Exit Sub
    15. End If
    16. ...
    17. ...
    18. End Sub



    die fertige Tonfolge kommt mir irgendwie ein wenig zu langsam vor


    Ich hab bei mir 'ne Stopwatch und Timespan laufen, die Pause ist 600.002MS oder so lang, also ziemlich genau.
    Und die Töne check ich nochmal ab, hatte aber auch gute Ergebnisse. Egal ich schau mir das an und wenn ich 'ne Lösung habe
    schick ich Dir das Projekt.

    Brauchst Du sonst noch was?

    mfg OnkelR
    Die Pause wird schon stimmen, ich meinte aber die Summe der Tonfolge, hatt die 350ms bzw. hat die einzelne Frequenz 70ms?

    Brauchen würde ich noch viel, aber ich bin schon mal froh, dass du mir bis hier geholfen hast!!

    Wenn ich nur den Code einigermassen verstehen würde, dann würde ich es ja selber machen! Wie gesagt, wenn du mir ein Sirenenprogramm erstellen könntest, dann versuche ich die anderen selbst, ich will ja auch was lernen :D

    Danke!!
    jo, die einzelnen Töne sind 70.00...MS lang - die Tonfolge 350MS. Ich mess das Morgen noch mal in Ruhe durch, ge.

    Na wenn du noch viel brauchst, dann machen wir eben noch viel.
    Wenn Du den Code nicht verstehst, frag mich doch einfach.
    Ich werde Dir ja noch'n Projekt senden, da mach ich mal ordentliche Kommentare rein, ok?

    Sirenenprogramm können wir doch machen. So Stück für Stück, damit Du's auch verstehst.
    Wir könnens auch über "Private Nachrichten" machen.
    Die stichpunktartigen Erklärungen helfen den anderen Usern eh nicht viel.
    Und ausserdem wollt ich sowieso mal ein Tutorial schreiben für's Forum. Mit kompletten Code und Erlaüterungen halt.

    sag was...
    Ja was soll ich sagen, ich hätte nicht erwartet, dass mir jemand so viel hilft und ich kann nur noch nochmal sagen, DANKE!

    Ich hab hier ein anderes ZVEI Programm, dort sind meiner Meinung die Tonfolgen schneller,(muss aber net heissen, dass das andere Programm stimmt) aber wahrscheinlich täusche ich mich da - der Pager muss auslösen, dass ist das wichtigste!


    Fragen hab ich viele, nur weiss ich garnicht wo ich anfangen soll! Der Code von dir ist mir zu hoch, ich habe bis jetzt solche Begriffe wie du sie geschrieben hast, noch nie gelesen, geschweige den benutzt, und weiss auch nicht, was die einzelnen tun! Es wäre toll, wenn jemand mal ein Projekt von Anfang an mit Erklärungen in einem Video erstellt, da könnte man viel lernen! Die Videos in Youtube sind nicht schlecht, aber es wird hier nicht wirklich in die Tiefe gegangen, was dies und das bedeutet und so weiter...

    Kennst du BOSTOOL, sowas würde ich benötigen, doch nur mit ZVEI und POCSAG und im Hintergrund wären die Feinenstellungen noch gut, wie Tonlänge und Pause ....

    Aber das ist zu viel verlangt und zu viel Arbeit!

    Tja, ich werde mir bis Morgen dein Projekt mal genauer anschauen, vielleicht blicke ich ja doch noch durch!
    Hallo zusammen,

    ich habe das Programm von OnkelR ausprobiert und bin total begeistert. Es funktioniert einwandfrei. Wir haben einmal im Jahr hier bei uns eine Großveranstaltung. Ich bin gerade dabei für diese Veranstaltung ein Programm zu programmieren welches es ermöglicht Aufträge, Einheiten, Fahrzeuge usw. zu disponieren und verwalten. Dafür möchte ich auch eine 5-Ton-Alarmierung einbauen. Mit dem Code von OnkelR würde dies funktionieren.

    Ich habe allerdings noch ein Problem mit dem Startbildschirm wenn die Bass.dll eingebunden wird. Dann erscheint nämlich ein Startbildschirm der Bass.NET API. Kann man diesen irgendwie unterbinden oder ausblenden? Oder gibt es eine kostenlose, schnelle und einfach Alternative?

    Grüße
    Jörg
    Hallo OnkelR,

    OnkelR schrieb:

    Chris, hier is maln Projekt, das hat zum Teil mit deinem Zeugs zu tun. Ich arbeite ja grad an
    was ähnlichem.vb-paradise.de/index.php/Attac…f3a7722d7c2430ba8345ffd58


    Das ist genau das, was ich suche.
    Ich suche eine Möglichkeit, 5-Tonfolgen und POCSAG-Alarmierungen mit vb.net zu Decodieren.

    Hast Du Dein Projekt für 5-Ton "BOS-Anwendung" noch weiterentwickelt?

    Hast Du auch eine Lösung zum Decodieren des POCSAG-Protokolls?

    Danke

    Gruß

    Marcel