FLAC
Flac Format

The flac format is used to play with a modern Diagital Analog Converter (DAC).
It is compressed but without any lost information, such as a mp3 file.
The sampling rate a to 192 kHz and a bitrate to 24 Bit.

I hear music with flacs, dsf and wav file with a T&A DAC 8 DSD.
But the Media Player I choose want to regist all files.
For me, that was uncomfortable, so I wrote MY own audio player.

Properties:
- There is a tree list for the folder of the solngs
- One can choose one or many folder to read the songs.
- The are read recursivly.
- The program can stop, start, and play behind and forward to the song.
- The program can change the volume ot the music.
- The program show the title, samplingrate and bitrate from the songs.

Therefore I have to read the mp3, wav and flac file, to read the informations.

Description_Audioplayer.pdf

AudioPlayer.exe
AudioPlayer.zip
AudioPlayer-Source.zip




Source in c#

using System;
using System.Collections.Generic;

using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.IO;
using System.Runtime.Serialization.Formatters.Binary;


namespace AudioPlayer.Tools {
  public class Flac {
    public String filename = "";
    public String album = "";
    public String artist = "";
    public String title = "";
    

    public int samplerate = 0;
    public int minutes = 0;
    public int seconds = 0;
    public int bitcount = 0;

    public Flac(String filename) {
      this.filename = filename;
    }

    public bool readSamplerate() {
      FileStream fin = new FileStream(this.filename, FileMode.Open, FileAccess.Read);
      BinaryReader bin = new BinaryReader(fin);
      // fLaC
      
      byte[] headerSoll = { 0x66, 0x4C, 0x61, 0x43 };
      byte[] header = new byte[headerSoll.Length];
      header = bin.ReadBytes(header.Length);
      for (int i = 0; i < headerSoll.Length; i++) {
        if (headerSoll[i] != header[i]) {
          Basis.ErrorMsg("Error, the audiofile is not a FLAC-File\r\n" + filename, "Error");
          bin.Close();
          fin.Close();
          return false;
        }
      }

      // samplerate
      fin.Seek(0x12,SeekOrigin.Begin); // jump to the first byte of the sampleRate
      
      byte[] samplerates = new byte[3];
      //dummy1 = bin.ReadBytes(dummy1.Length);
      samplerates = bin.ReadBytes(samplerates.Length); // adr: 12=byte[0], 13=byte[1], 14=byte[2]  Bits: 12+13+ highbyte(14)
      int b0 = samplerates[0];
      int b1 = samplerates[1];
      int b2 = samplerates[2];
      samplerate = (b0 << 12) | (b1 << 4) | (b2 >> 4); // 192 kHz

      //fin.Seek(0x12, SeekOrigin.Begin); // jump to the first byte of the sampleRate

      byte[] samplescount = new byte[5];
      samplescount = bin.ReadBytes(samplescount.Length); // 0x15 bis 0x19 von 0x15 nur die unteren bits
      int sc0 = samplescount[0] & 0xF;
      int sc1 = samplescount[1];
      int sc2 = samplescount[2];
      int sc3 = samplescount[3];
      int sc4 = samplescount[4];
      long scount = (sc0 << 32) | (sc1 << 24) | (sc2 << 16) | (sc3 << 8) | sc4;
      long seconds = (long) (scount / samplerate);
      this.minutes = (int)(seconds / 60.0);
      this.seconds = (int)(seconds % 60);


      byte[] channels = new byte[3];
      channels = bin.ReadBytes(channels.Length); // 0x15 bis 0x19 von 0x15 nur die unteren bits

      int bitcount0 = samplescount[0] >> 4; // F
      int bitcount1 = samplerates[2] & 0xF; // 2
      bitcount = (bitcount1<<4) | bitcount0;
      // es sind nur 5 Bit zuständig
      bitcount = bitcount >> 3;

      /*  https://xiph.org/flac/format.html#def_STREAMINFO
      000 : get from STREAMINFO metadata block
  001 : 8 bits per sample
  010 : 12 bits per sample
  011 : reserved
  100 : 16 bits per sample
  101 : 20 bits per sample
  110 : 24 bits per sample
  111 : reserved
  */

      if (bitcount==5) {
        bitcount = 16;
      }
      else if (bitcount == 6) {
        bitcount = 24;
      }
      else {
        Basis.ErrorMsg("Error to get the bits/sample\r\nPlease send an email to mwilhelm@hs-harz.de", "Error");
        bitcount = -1;
      }

        bin.Close();
      fin.Close();      
      return true;
    }
    /*

  000 : get from STREAMINFO metadata block
  001 : 8 bits per sample
  010 : 12 bits per sample
  011 : reserved
  100 : 16 bits per sample
  101 : 20 bits per sample
  110 : 24 bits per sample
  111 : reserved

 *     */

    public bool readTexte() {
      FileStream fin = new FileStream(this.filename, FileMode.Open, FileAccess.Read);
      BinaryReader bin = new BinaryReader(fin);
      // fLaC
      
      byte[] headerSoll = { 0x66, 0x4C, 0x61, 0x43 };
      byte[] header = new byte[headerSoll.Length];
      header = bin.ReadBytes(header.Length);
      for (int i1 = 0; i1 < headerSoll.Length; i1++) {
        if (headerSoll[i1] != header[i1]) {
          Basis.ErrorMsg("Error, the audiofile is not a FLAC-File\r\n" + filename, "Error");
          bin.Close();
          fin.Close();
          return false;
        }
      }


      fin.Seek(0, SeekOrigin.Begin);
      byte[] bytes = new byte[10000];
      bytes = bin.ReadBytes(bytes.Length);
      // suche reference, dann ALBUMARTIST, ALBUM  TITLE title
      
      String searchItem = "reference";
      bool reference = false;
      int i = 0;
      byte b = 0;
      int positionReference = searchString(bytes, searchItem);
      if (positionReference == -1) {
        int p1 = searchString(bytes, "ALBUM=");
        int p2 = searchString(bytes, "TITLE=");
        int p3 = searchString(bytes, "title=");
        int p4 = searchString(bytes, "ARTIST=");
        if (p1 > 0 && p4 > 0 && (p2 > 0 || p3 > 0)) {
          // nun gibt es doch einträge
          bin.Close();
          fin.Close();
          // nun weiter siehe unten
        }
        else {
          Basis.ErrorMsg("Error, the audiofile has not a reference-Block\r\n" + filename, "Error");
          bin.Close();
          fin.Close();
          return false;
        }
      }
      else {
        positionReference += searchItem.Length; // Position auf das Byte nach der reference setzen
        fin.Seek(positionReference, SeekOrigin.Begin);
        bytes = bin.ReadBytes(bytes.Length); // nun nach reference lesen
        bin.Close();
        fin.Close();
      }

      album = "Please send an email to me!";
      artist = "Please send an email to me!";
      title = "Please send an email to me!";
      searchItem = "ALBUM=";
      int position = searchString(bytes, searchItem);
      if (position == -1) {
        searchItem = "Album=";
        position = searchString(bytes, searchItem);
        if (position == -1) {
          searchItem = "album=";
          position = searchString(bytes, searchItem);
          if (position == -1) {
            Basis.ErrorMsg("Error, the audiofile has no ALBUM-Text\r\n" + filename, "Error");
            return false;
          }
        }
      }
      position += searchItem.Length;
      album = searchTextUntilZero(bytes, position);

      // -----------------------------------------
      searchItem = "TITLE=";
      position = searchString(bytes, searchItem);
      if (position==-1) {
        searchItem = "Title=";
        position = searchString(bytes, searchItem);
        if ((position == -1) ) {
          searchItem = "title=";
          position = searchString(bytes, searchItem);
          if ((position == -1)) {
            Basis.ErrorMsg("Error, the audiofile has no TITLE-Text\r\n" + filename, "Error");
            return false;
          }
        }
      }
      if (position > 0) {
        title = searchTextUntilZero(bytes, position);
      }


      searchItem = "ARTIST=";
      position = searchString(bytes, searchItem);
      if (position == -1) {
        searchItem = "Artist=";
        position = searchString(bytes, searchItem);
        if ((position == -1)) {
          searchItem = "artist=";
          position = searchString(bytes, searchItem);
          if ((position == -1)) {
            Basis.ErrorMsg("Error, the audiofile has no Artist-Text\r\n" + filename, "Error");
            return false;
          }
        }
      }
      if (position > 0) {
        artist = searchTextUntilZero(bytes, position);
      }


      return true;
    } // readTexte

    private String searchTextUntilZero(byte[] bytes, int position) {
      StringBuilder sb = new StringBuilder();
      for (int i=position; i=32) {
            if (bytes[i] == 0xC3 && bytes[i+1] == 0xBC) {
              sb.Append("ü");
              i++;
            }
            else {
              sb.Append((char)bytes[i]);
            }              
          }
        }
      }
      return sb.ToString();
    } // searchTextUntilZero

    private int searchString(byte[] bytes, String searchItem) {
      int position = -1;
      byte[] searchItemBytes = new byte[searchItem.Length]; // Unicode !!
      for (int i = 0; i < searchItem.Length; i++) {
        searchItemBytes[i] = (byte)searchItem[i];
      }
      for(int i =0; i< bytes.Length;i++) {
        if (bytes[i] == searchItemBytes[0]) {
          // prüfe die Länge
          bool okay = true;
          for (int j = 0; j < searchItem.Length; j++) {
            if (i + j < bytes.Length) {
              if (bytes[i + j] != searchItemBytes[j]) { // error bei Paul Simon #14
                okay = false;
                break;
              }
            }
            else {
              break;
            }
          }
          if (okay) {
            position = i;
          }
        }
      }

      return position;
    }



  }
}