Avatar billede anderskj1 Nybegynder
13. april 2003 - 18:56 Der er 19 kommentarer og
1 løsning

[NØD!] Dannelse af et musikformat på bitniveau

Jeg (vi) er ved at lave et musikformat med kompression. Dette medfører at vi skal gemme data med forskellig bitlængde alt efter hvad codec bestemmer. Formatet er flg.

|12x1bit|25x4bit|25x4bit|!!512 tal med variable bit længde mellem 2-16 bit!!|

Dvs. de færste 212 bit er altid fast. Hverefter der skal gemmes 512 tal efter hinanden med forskellige bitlængder.

Jeg har prøvet at arbejde med bitfields som vidst i koden neden under. Men det giver den del spilds plads. fx. ved 9 bit vil jeg spilde 7 bits for hvert tal hvilket er uacceptabelt. For så kunne vi lige så godt vælge at bruge 16 bit. Nogen forslag til en anden løsnning? Eller udbygget?

typedef unsigned short int bit;

typedef struct
{
union
{
  bit bit16;

  struct
  {
  bit bit1  : 2;
  bit bit2  : 2;
  bit bit3  : 2;
  bit bit4  : 2;
  bit bit5  : 2;
  bit bit6  : 2;
  bit bit7  : 2;
  bit bit8  : 2;
  bit bit9  : 2;
  bit bit10 : 2;
  bit bit11 : 2;
  bit bit12 : 2;
  bit bit13 : 2;
  bit bit14 : 2;
  bit bit15 : 2;
  bit bit16 : 2;
  } bitfield1;

  struct
  {
  bit bit1_3  : 3;
  bit bit4_6  : 3;
  bit bit7_9  : 3;
  bit bit10_13 : 3;
  bit bit14_16 : 3;
  } bitfield3;

  struct
  {
  bit bit1_4  : 4;
  bit bit5_8  : 4;
  bit bit9_12  : 4;
  bit bit13_16 : 4;

  } bitfield4;

  struct
  {
  bit bit1_5  : 5;
  bit bit6_10  : 5;
  bit bit11_15 : 5;

  } bitfield5;

// ====OSV ..
struct
  {
  bit bit1_9  : 9;//her er jo alt for meget spildplads.

  } bitfield9;
// ====OSV...
}Data;

main()
{
  Data t;
  t.bit bit1_5 = 23;
  // OSv...
}
Avatar billede arne_v Ekspert
13. april 2003 - 19:02 #1
Drop de structs og lav noget kode som kan put og get bits
i et char array.
Avatar billede arne_v Ekspert
13. april 2003 - 19:05 #2
Jeg har f.eks. i nogle applikatione rbrugt en klasse:

class BitString {
  private:
      // body of bytes
      char *Body;
      // length of body in bytes
      int Len;
      // current position in bits
      int CurrPos;
  public:
      // constructor
      BitString();
      // destructor
      ~BitString();
      // add bits
      void AddBits(int Value,int NoBits);
      // get bits
      int GetBits(int NoBits);
      ...
}
Avatar billede arne_v Ekspert
13. april 2003 - 19:07 #3
Skulle jeg evt. prøve at cutte den relevante kode ud til jer ?
Avatar billede anderskj1 Nybegynder
13. april 2003 - 19:10 #4
Det må du meget gerne Arne. Kan ikke helt se hvor du vil hen med din kode. Men hvis du har noget kode osm gør det muligt at "appende" et tal med bitlængde X til et eksisterende array af fx. Chars ville det jo være fantastisk.
Avatar billede arne_v Ekspert
13. april 2003 - 19:18 #5
tstbits.cpp
===========

#include <stdlib.h>

#include <iostream>

using namespace std;

#include "bits.h"

void test()
{
  int i;
  class BitString X,Y,Z;
  // pack some integers of various length
  for(i=0;i<8;i++) {
      X.AddBits(1,1);
      X.AddBits(3,2);
      X.AddBits(7,3);
      X.AddBits(15,4);
      X.AddBits(1917,16);
  };
  // get the resulting string and copy it
  int l;
  char tmp[100];
  cout << X.SizeString() << endl;
  X.GetString(tmp,sizeof(tmp),&l);
  Y.SetString(tmp,l);
  // unpack the integers
  while(!Y.EndString(1+2+3+4+16)) {
      cout << Y.GetBits(1) << endl;
      cout << Y.GetBits(2) << endl;
      cout << Y.GetBits(3) << endl;
      cout << Y.GetBits(4) << endl;
      cout << Y.GetBits(16) << endl;
  }
  // pack a lot of bits
  for(i=0;i<100000;i++) Z.AddBits(1,1);
  cout << Z.SizeString() << endl;
  return;
}

int main()
{
  test();
  exit(EXIT_SUCCESS);
}
Avatar billede arne_v Ekspert
13. april 2003 - 19:18 #6
bits.h
======

#ifndef BITS_H
#define BITS_H

// various
#define MIN(a,b) ((a<b)?a:b)
typedef unsigned char UCHAR;
typedef int BOOL;
const int BITS_PR_CHAR = 8;

//**********************************************************************
//
//  Class definitions:
//
//    BitString : char array containing bits
//
//**********************************************************************

// class for char array containing bits
class BitString {
  private:
      // body of bytes
      char *Body;
      // length of body in bytes
      int Len;
      // current position in bits
      int CurrPos;
  public:
      // constructor
      BitString();
      // destructor
      ~BitString();
      // add bits
      void AddBits(int Value,int NoBits);
      // get bits
      int GetBits(int NoBits);
      // set string
      void SetString(void *Buffer,int Size);
      // get string
      void GetString(void *Buffer,int BufferSize,int *ReturnLen);
      void GetStringRev(void *Buffer,int BufferSize,int *ReturnLen);
      // end of string ?
      BOOL EndString(int Size = 0);
      // size of string
      int SizeString();
  };

#endif // BITS_H
Avatar billede arne_v Ekspert
13. april 2003 - 19:19 #7
bits.cpp
========

#include <string.h>

#include "bits.h"

// size of chunks memory are allocated in
const int ALLOCATE = 1000;

// calculate length in bytes from current position in bits
#define CURRLEN ((CurrPos+(BITS_PR_CHAR-1))/BITS_PR_CHAR)

const int bits_reverse[256] = {
0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,
0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,
0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,
0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,
0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,
0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,
0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,
0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,
0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,
0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,
0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,
0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,
0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,
0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,
0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,
0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,
0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF};

//**********************************************************************
//
//  Class BitString
//
//**********************************************************************

// constructor
BitString::BitString()
{
  Len = ALLOCATE;
  Body = new char[Len];
  memset(Body,0,Len);
  CurrPos = 0;
}

// destructor
BitString::~BitString()
{
  delete Body;
}

// add bits
void BitString::AddBits(int Value,int NoBits)
{
  // allocate more memory if needed
  if((CurrPos+NoBits)>=(Len*BITS_PR_CHAR)) {
      char *tmp = new char[Len];
      memcpy(tmp,Body,Len);
      delete Body;
      Len = Len + ALLOCATE;
      Body = new char[Len];
      memcpy(Body,tmp,Len-ALLOCATE);
      memset(Body+Len-ALLOCATE,0,ALLOCATE);
      delete tmp;
  }
  // append bits as part byte,whole byte,...,whole byte,part byte
  int bitix = CurrPos % BITS_PR_CHAR;
  int bytix = CurrPos / BITS_PR_CHAR;
  int v = Value;
  int nb = NoBits;
  int l,d;
  while(nb>0) {
      l = MIN(nb,BITS_PR_CHAR-bitix);
      d = 1 << l;
      Body[bytix] = Body[bytix] | ((v%d) << bitix);
      bitix = 0;
      bytix++;
      v = v / d;
      nb = nb - l;
  }
  CurrPos = CurrPos + NoBits;
  return;
}

// get bits
int BitString::GetBits(int NoBits)
{
  // extract bits as part byte,whole byte,...,whole byte,part byte
  int bitix = CurrPos % BITS_PR_CHAR;
  int bytix = CurrPos / BITS_PR_CHAR;
  int res = 0;
  int nb = NoBits;
  int l;
  while(nb>0) {
      l = MIN(nb,BITS_PR_CHAR-bitix);
      res = res + (((Body[bytix] >> bitix) & (~(-1 << l))) << (NoBits - nb));
      bitix = 0;
      bytix++;
      nb = nb - l;
  }
  CurrPos = CurrPos + NoBits;
  return res;
}

// set string
void BitString::SetString(void *Buffer,int Size)
{
  // simple copy
  delete Body;
  Len = Size;
  Body = new char[Len];
  memcpy(Body,Buffer,Size);
  CurrPos = 0;
  return;
}

// get string
void BitString::GetString(void *Buffer,int BufferSize,int *ReturnLen)
{
  // simple copy
  *ReturnLen = MIN(BufferSize,CURRLEN);
  memcpy(Buffer,Body,*ReturnLen);
  return;
}

void BitString::GetStringRev(void *Buffer,int BufferSize,int *ReturnLen)
{
  // call GetString and reverse bits in all bytes in string
  GetString(Buffer,BufferSize,ReturnLen);
  for(int i=0;i<(*ReturnLen);i++)
      ((char *)Buffer)[i] = bits_reverse[UCHAR(((char *)Buffer)[i])];
  return;
}

// end of string ?
BOOL BitString::EndString(int size)
{
  return ((CurrPos+size)>=(Len*BITS_PR_CHAR));
}

// size of string
int BitString::SizeString()
{
  return CURRLEN;
}
Avatar billede arne_v Ekspert
13. april 2003 - 19:22 #8
I kan se brugen i testbits.cpp:

Groft laver man bare en BitString og ligger bits ind med:
  AddBits(int-value,antal-bits)
og henter char array ud med SizeString og GetString.

Når man skal have dem ud igen, så putter man char array ind med
SetString og henter med:
  GetBits(antal-bits)
Avatar billede arne_v Ekspert
13. april 2003 - 19:23 #9
Koden er nok ikke helt "moderne" (den er skrevet engang ca. 1995).

Men den er rimeligt veltestet.

I kan bare ignorere ting I ikke skal bruge f.eks. det der reverse
halløjsa.
Avatar billede anderskj1 Nybegynder
13. april 2003 - 19:49 #10
Det ser meget interesant ud. Men hvis jeg gør sådan her:
X.AddBits(1,1);
X.AddBits(3,2);
X.AddBits(7,3);
X.AddBits(15,4);
X.AddBits(1917,16);

Skuller gerne give noget i omegenen af 26 bits.

Men cout << "Storrelse i bits: " << sizeof(X)*8 << endl;

giver 96 bits. Altså et ret stor "spild" ift. de nødvendige 26, som jo ville fylde 32 bit.

Er det mig der har misforstået noget eller?
Avatar billede arne_v Ekspert
13. april 2003 - 19:53 #11
Der er ingen spild-plads i BitString, bortset fra oprunfing til et
helt antal bytes.

sizeof(X) returnerer den mængde data BiTString objektet bruger ialt
til data og alt muligt andet.

Brug X.SizeString() til at få størrelsen i bytes.
Avatar billede anderskj1 Nybegynder
13. april 2003 - 20:08 #12
sizeof(X) returnerer den mængde data BiTString objektet bruger ialt
til data og alt muligt andet.

Ja. Men når jeg skal til at gemme dette objekt i en fil (hvilket er meningen) er det reele pladsforbrug vel det sizeof viser mig?
Avatar billede anderskj1 Nybegynder
13. april 2003 - 20:12 #13
OK. Tror jeg lige jeg forvirrede mig selv. sizeof viser vel den statiske størrelse objektet fylder. Og dette overhead er der jo kun for hvert objekt (som jeg jo kun får et af) Er dette rigtig fortået?
Avatar billede arne_v Ekspert
13. april 2003 - 20:13 #14
Du skal ikke gemme selve BitString objektet.

Det er kun en transformator.

Du laver et BitString objekr, du tilføjer en masse bits
med AddBits, så finder du længden med SizeString, allokerer
et char array af denb størrelse og henter det med GetString,
og så gemmer du det char array i filen.
Avatar billede anderskj1 Nybegynder
13. april 2003 - 20:16 #15
OK. Det her lyder næsten for perfekt. Jeg kigger på det i aften. Du får i hvert fald hele point puljen for din hjælp. Men jeg venter lige med at afslutte tråden her til lidt snere.
Avatar billede arne_v Ekspert
13. april 2003 - 20:16 #16
sizeof vil iøvrigt normalt altid returnere 12 uanset hvor mange bits
der er gemt i det, fordi det kun indeholder en pointer til dets
interne char array.
Avatar billede arne_v Ekspert
13. april 2003 - 20:17 #17
I er ikke de eneste der har haft behov for at gemme bits.

Den klasse er lavet lige præcis til formålet at gemme felter af
variabel bit-længde.
Avatar billede anderskj1 Nybegynder
13. april 2003 - 21:12 #18
lol. Har siddet og teste lidt frem og tilbage det ser sgu ud til at det var lige præcis hvad jeg malgede. MEN kan du fortælle mig hvofor jeg ikke kan allokere chararrayet dynamisk?

char *HentetBits = new char[5];
//    char HentetBits[5];

Når jeg gør det dynmaisk burde jeg selvfølgelig bruge X.SizeString() men der er ingen forskel. Der er ligsom der ikke er plads i arrayet.
Avatar billede arne_v Ekspert
13. april 2003 - 21:32 #19
char* tmp = new char[X.SizeString()];
X.GetString(tmp,X.SizeString(),&l);

burde virke.

char* tmp = new char[X.SizeString()];
X.GetString(tmp,sizeof(tmp),&l);

virker naturligvis ikke (sizeof en char pointer ar altid 4).
Avatar billede anderskj1 Nybegynder
13. april 2003 - 21:40 #20
Fandt ud af det. Tusind tak for hjælpen. Jeg er en gladere mand nu :)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester