Avatar billede psycosoft-funware Nybegynder
05. januar 2007 - 23:10 Der er 6 kommentarer og
1 løsning

problemer med bitrate kalkulering

nu må jeg bede om hjælp igen :)

lidt baggrund:
mit problem er at jeg skal kalkulere bitraten for Ogg Vorbis lydformatet for indkoderen. det jeg skal kalkulere er Quality index;

jeg har en ScrollBar der er sat til: Min: -100; Max: 1000;
det beregnes med D := SbVorbisQ.Position / 100;

hovedproblemet:
jeg har lavet følgende funktion der skal tage det beregnede overstående kommatal og beregne den tilhørende bitrate i kbps;

function TConfigOutputDlg.CalcVorbisBitrate(FloatValue: Double): String;
var
  EstBitrate: Double;
  MultA: Double;
  MultB: Double;
  QualityA, QualityB: Double;
  S: String;
  Tmp: String;
  Tmp2: String;
begin
  S := '1,0';
  Tmp2 := '0,0';
  MultB := StrToFloat(Tmp2);
  QualityA := FloatValue;
  QualityB := QualityA + 1;
  if (QualityB > 10) then
      QualityB := 10;
  if (FloatValue > 0) then
      MultB := FloatValue - QualityA;
  MultA := StrToFloat(S) - MultB;
  EstBitrate := (MultA * 80 + QualityA + 1) + (MultB * 80 + QualityB + 1);
  Tmp := StringReplace(FormatFloat('0.00', FloatValue), ',', '.', [rfReplaceAll, rfIgnoreCase]) + ' (~' + FloatToStr(EstBitrate) + ' kbps)';
  Result := Tmp;
end;

hvor er det jeg klokker i det?;

det skal passe med at når kommatallet er -1.00 svare bitraten til 45 kbps og når den er 10.00 svare det til 500 kbps.

/psycosoft-funware :)
Avatar billede hrc Mester
07. januar 2007 - 00:28 #1
Hvorfor er det nødvendigt at bruge strenge i de beregninger. Meget forvirrende - generelt en meget rodet funktion hvor man på parameteren ikke kan se hvilken værdi der sendes. Hvis nu du skrev aVorbisRatio eller lignende så var man ikke i tvivl.

I øvrigt kan du lave "QualityB := min(QualityB,10)" i stedet for din "if then" (jeg kan godt lide one-lineres)

Optimerede lidt på din funktion og nåede frem til dette her:

function TfrmMain.CalcVorbisBitrate(const aVorbisRatio: Double): String;
var
  EstBitrate: Double;
  MultA, MultB: Double;
  QualityA, QualityB: Double;
  FormatSettings : TFormatSettings;
begin
  QualityA := aVorbisRatio;
  QualityB := min(QualityA + 1,10);
  MultB := min(aVorbisRatio,0.0); // Hvis VR > 0 så sæt MultiB = 0
  MultA := 1.0 - MultB;
  EstBitrate := (MultA * (80 + QualityA + 1)) + (MultB * (80 + QualityB + 1));

  EstBitrate := (aVorbisRatio + 2) * 45;

  FormatSettings.DecimalSeparator := '.';
  result := format('%s (~%s kbps)',[FormatFloat('0.00', aVorbisRatio, FormatSettings),
                                    FloatToStr(EstBitrate,FormatSettings)]);
end;

Derefter forstod jeg hvad du havde gang i (tror jeg nok) og lavede dette her i stedet for:

function TfrmMain.CalcVorbisBitrate(const aVorbisRatio: Double): String;
var
  FormatSettings : TFormatSettings;
begin
  FormatSettings.DecimalSeparator := '.';
  result := format('%s (~%s kbps)',[FormatFloat('0.00', aVorbisRatio, FormatSettings),
                                    FloatToStr((aVorbisRatio + 2) * 45,FormatSettings)]);
end;

10 svarer godt nok til 540kbit men da det er et estimat er det vel ok.
Avatar billede psycosoft-funware Nybegynder
07. januar 2007 - 19:58 #2
ja jeg ved godt det er noget rod (flovt)
det jeg har arbejdet ud fra er en opensource cd ripper kaldet CDex, så det er nok ikke så underligt at min oversættelse af en stump kode blev en gang gylle :(

koden jeg har fokuseret ud fra er som følgende:
void CEncoderVorbidDllDlg::UpdateQualityControlValue()

/*
** Copyright (C) 1999 - 2002 Albert L. Faber
** 
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include "stdafx.h"
#include "cdex.h"
#include "EncoderVorbisDllDlg.h"
#include "Encode.h"
#include <math.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static int oggBitrates[] = { 0,32,40,48,64,80,96,128,160,196,256,350};


static int QualityNominalBitrateRelation[][2] = {
    { -1, 45 },
    {  0, 64 },
    {  1, 80 },
    {  2, 96 },
    {  3, 112 },
    {  4, 128 },
    {  5, 160 },
    {  6, 192 },
    {  7, 224 },
    {  8, 256 },
    {  9, 320 },
    {  9, 500 }
};



CEncoderVorbidDllDlg::CEncoderVorbidDllDlg()
    : CEncoderDlg(CEncoderVorbidDllDlg::IDD)
{
    //{{AFX_DATA_INIT(CEncoderVorbidDllDlg)
    m_nMode = -1;
    m_nChannels = -1;
    m_strQualitySetting = _T("");
    m_bUseQualitySetting = FALSE;
    //}}AFX_DATA_INIT
    m_bEncDuringRead = FALSE;
}


void CEncoderVorbidDllDlg::DoDataExchange(CDataExchange* pDX)
{
    CEncoderDlg::DoDataExchange(pDX);
    //{{AFX_DATA_MAP(CEncoderVorbidDllDlg)
    DDX_Control(pDX, IDC_QUALITYSETTINGSCROLL, m_QualityScroll);
    DDX_Control(pDX, IDC_MINBITRATE, m_MinBitrate);
    DDX_Control(pDX, IDC_BITRATE, m_Bitrate);
    DDX_Control(pDX, IDC_MAXBITRATE, m_MaxBitrate);
    DDX_Check(pDX, IDC_RTENCODING, m_bEncDuringRead);
    DDX_Radio(pDX, IDC_CHANNELSELECTION, m_nChannels);
    DDX_Text(pDX, IDC_QUALITYSETTING, m_strQualitySetting);
    DDX_Check(pDX, IDC_USEQUALITYSETTING, m_bUseQualitySetting);
    //}}AFX_DATA_MAP
}




BEGIN_MESSAGE_MAP(CEncoderVorbidDllDlg, CEncoderDlg)
    //{{AFX_MSG_MAP(CEncoderVorbidDllDlg)
    ON_WM_HSCROLL()
    ON_BN_CLICKED(IDC_USEQUALITYSETTING, OnUsequalitysetting)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CEncoderVorbidDllDlg message handlers

BOOL CEncoderVorbidDllDlg::OnInitDialog()
{
    CEncoderDlg::OnInitDialog();

    // translate dialog resources
    g_language.InitDialogStrings( this, IDD );

    // setup scroll range, 0.01 precission CScrollBar
    m_QualityScroll.SetScrollRange( -100, 1000 );

    return TRUE;
}


void CEncoderVorbidDllDlg::GetControls(CEncoder* pEncoder)
{
    // Get data out of Controls
    UpdateData(TRUE);

    // Set items
    pEncoder->SetOnTheFlyEncoding(m_bEncDuringRead);

    int nMode = ( m_nChannels  == 1 ) ? BE_MP3_MODE_MONO : BE_MP3_MODE_STEREO;

    pEncoder->SetMode( nMode );

    // Get bitrate selection
    pEncoder->SetMinBitrate( oggBitrates[ m_MinBitrate.GetCurSel() ] );
    pEncoder->SetBitrate( oggBitrates[ m_Bitrate.GetCurSel() ] );
    pEncoder->SetMaxBitrate( oggBitrates[ m_MaxBitrate.GetCurSel() ] );

    pEncoder->SetUserN1( MAKELPARAM( m_QualityScroll.GetScrollPos(), m_bUseQualitySetting ) );

}



void CEncoderVorbidDllDlg::FillBitrateTables()
{
    CString strLang;

    // Depending on the settings, fill the bit-rate tables
    m_MinBitrate.ResetContent();

    int nItems = sizeof( oggBitrates ) / sizeof( oggBitrates[ 0 ] );

    strLang = g_language.GetString( IDS_DEFAULT );

    m_Bitrate.AddString( strLang );
    m_MaxBitrate.AddString( strLang );
    m_MinBitrate.AddString( strLang );

    // DO NOT DISPLAY ITEM 0
    for (int i=1;i<nItems;i++)
    {
        CString strItem;
        strItem.Format( _T( "%d kbps" ), oggBitrates[ i ] );

        m_MinBitrate.AddString(strItem);
        m_Bitrate.AddString(strItem);
        m_MaxBitrate.AddString(strItem);
    }
}

void CEncoderVorbidDllDlg::SetBitrates(int min_br,int nom_br, int max_br)
{
    int nItems=sizeof(oggBitrates)/sizeof(oggBitrates[0]);
   
    m_MinBitrate.SetCurSel(0);
    m_Bitrate.SetCurSel(0);
    m_MaxBitrate.SetCurSel(0);

    for (int i=1;i<nItems;i++)
    {
        if (min_br==oggBitrates[i])
        {
            m_MinBitrate.SetCurSel(i);
        }
        if (nom_br==oggBitrates[i])
        {
            m_Bitrate.SetCurSel(i);
        }
        if (max_br==oggBitrates[i])
        {
            m_MaxBitrate.SetCurSel(i);
        }
    }

}


void CEncoderVorbidDllDlg::SetControls(CEncoder* pEncoder)
{
    INT nMode = pEncoder->GetMode();

    // Set control items based in pEncoder information
    m_bEncDuringRead=pEncoder->GetOnTheFlyEncoding();

    m_nChannels = ( ( nMode & 0xFFFF ) == BE_MP3_MODE_MONO )? 1 : 0;

    // Fill Min bitrate table
    FillBitrateTables();

    // Set the proper bitrate
    SetBitrates(pEncoder->GetMinBitrate(),pEncoder->GetBitrate(),pEncoder->GetMaxBitrate());

    m_QualityScroll.SetScrollPos( (SHORT)(LOWORD( pEncoder->GetUserN1() ) ) );

    m_bUseQualitySetting = HIWORD( pEncoder->GetUserN1() );

    m_MinBitrate.EnableWindow( m_bUseQualitySetting == 0 );
    m_Bitrate.EnableWindow( m_bUseQualitySetting == 0 );
    m_MaxBitrate.EnableWindow( m_bUseQualitySetting == 0 );

    m_QualityScroll.EnableWindow( m_bUseQualitySetting );
    m_QualityScroll.EnableScrollBar( m_bUseQualitySetting ? ESB_ENABLE_BOTH : ESB_DISABLE_RTDN );

    UpdateQualityControlValue();

    // Set data to controls
    UpdateData(FALSE);
}

void CEncoderVorbidDllDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
    // Get data from controls
    UpdateData( TRUE );

    CEncoderDlg::OnHScroll( nSBCode, nPos, pScrollBar );

    switch ( nSBCode )
    {
        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            pScrollBar->SetScrollPos( nPos );
        break;
        case SB_LINELEFT:
            pScrollBar->SetScrollPos( m_QualityScroll.GetScrollPos() - 1 );
        break;
        case SB_LINERIGHT:
            pScrollBar->SetScrollPos( m_QualityScroll.GetScrollPos() + 1 );
        break;
    }

    UpdateQualityControlValue();

    UpdateData( FALSE );

}

void CEncoderVorbidDllDlg::UpdateQualityControlValue()
{
    DOUBLE dQuality = (DOUBLE)m_QualityScroll.GetScrollPos() / 100.0;
    DOUBLE dEstBitrate = 0.0;
    DOUBLE dMultA = 0.0;
    DOUBLE dMultB = 0.0;
    INT        nQualityA = 0;
    INT        nQualityB = 0;
   
    nQualityA = floor( dQuality );
    nQualityB = nQualityA + 1;

    if ( nQualityB > 10 )
    {
        nQualityB = 10;
    }

    if ( dQuality > 0 )
    {
        dMultB = dQuality - nQualityA;
    }
    else
    {
        dMultB = dQuality - nQualityA;
    }

    dMultA = ( 1.0 - dMultB );

    dEstBitrate =    dMultA * (DOUBLE)QualityNominalBitrateRelation[ nQualityA + 1 ][1] +
                    dMultB * (DOUBLE)QualityNominalBitrateRelation[ nQualityB + 1 ][1];

    // update info
    m_strQualitySetting.Format( _T( "%5.2f (~%3d kbps)" ), dQuality, (int)( dEstBitrate + 0.5 ) );
   
}


void CEncoderVorbidDllDlg::OnUsequalitysetting()
{
    // Get data from controls
    UpdateData( TRUE );

    m_MinBitrate.EnableWindow( m_bUseQualitySetting == 0 );
    m_Bitrate.EnableWindow( m_bUseQualitySetting == 0 );
    m_MaxBitrate.EnableWindow( m_bUseQualitySetting == 0 );

    m_QualityScroll.EnableWindow( m_bUseQualitySetting );
    m_QualityScroll.EnableScrollBar( m_bUseQualitySetting ? ESB_ENABLE_BOTH : ESB_DISABLE_RTDN );

    // Set data to controls
    UpdateData(FALSE);

}

UINT CEncoderVorbidDllDlg::GetIDD()
{
    return IDD;
}

håber du kan se hvor jeg vil hen :)
Avatar billede hrc Mester
10. januar 2007 - 09:52 #3
Joee. Det kan jeg da og det ser da også ud til du stort set har porteret rutinen - men skal det være 500 på toppen og ikke sådan som min funktion skriver, 540?

Man kan jo hacke det lidt og sige at hvis aVorbisRatio = 10 så er bitraten 500, alle andre steder kan man så beregne den. Det er ikke kønt.
Uden at kende en fløjtende fjært til Vorbis ellers, så vil jeg da synes at 540 er det rigtige resultat.
Avatar billede psycosoft-funware Nybegynder
10. januar 2007 - 20:44 #4
der hvor de kokser (hos mig, ihverfald) er i denne linje:
dEstBitrate =    dMultA * (DOUBLE)QualityNominalBitrateRelation[ nQualityA + 1 ][1] +
                    dMultB * (DOUBLE)QualityNominalBitrateRelation[ nQualityB + 1 ][1];
hvad menes der med: QualityNominalBitrateRelation[ nQualityB + 1 ][1] ? og hvordan er det  kædet sammen med listen:
static int QualityNominalBitrateRelation[][2] = {
    { -1, 45 },
    {  0, 64 },
    {  1, 80 },
    {  2, 96 },
    {  3, 112 },
    {  4, 128 },
    {  5, 160 },
    {  6, 192 },
    {  7, 224 },
    {  8, 256 },
    {  9, 320 },
    {  9, 500 }
};

:)
Avatar billede hrc Mester
10. januar 2007 - 22:27 #5
Han slår simpelthen op i konstant som er en matrice, så QualityNominalBitrateRelation[x][1] slår op i den sidste kolonne, dvs. tallene 45, 64, 80, 96 ...). Umiddelbart bruges den første kolonne ikke - ser ud til at være med af informative grunde.

I Delphi kan du lave det samme (gider ikke skrive det lange navn). Som nævnt tidligere behøver du tilsyneladende ikke den første kolonne:

function TfrmMain.CalcVorbisBitrate2(const aVorbisQuality: Double): String;
const
  QNBR : array[-1..10] of integer = (45,64,80,96,112,128,160,192,224,256,320,500);
var
  dMultA : double;
  dMultB : double;
  nQualityA : integer;
  nQualityB : integer;
  dEstBitrate : double;
begin
  nQualityA := floor(aVorbisQuality);
  nQualityB := min(nQualityA + 1,10);

  dMultB := min(aVorbisQuality,0.0); // Et gæt for der er fejl i den oprindelige kode
  dMultA := 1.0 - dMultB;

  dEstBitrate := dMultA * QNBR[nQualityA] + dMultB * QNBR[nQualityB];
  result := format('%5.2f (~%3d kbps)',[aVorbisQuality, round(dEstBitrate + 0.5)]);
end;

procedure TfrmMain.tbVorbisChange(Sender: TObject);
begin
  ePosition.Text := format('%d',[tbVorbis.Position]);
  eStatus.Text := CalcVorbisBitrate2(tbVorbis.Position / 100);
end;
Avatar billede psycosoft-funware Nybegynder
11. januar 2007 - 19:04 #6
hrc, jeg må endnu end gang tage hatten af for din delphi ekspertise, takker mange gange :)

btw, må jeg tilføje dig til min msn? :)
Avatar billede psycosoft-funware Nybegynder
11. januar 2007 - 20:11 #7
>>hrc: jeg har lavet en lille rettelse i koden der nu har fået det til at virke ultima perfectus :D jeg vil endnu end gang takke for din indsats og ikke minst for din tolmodighed for mine spørgsmål.
her er så det endelige resultat:
function TConfigOutputDlg.CalcVorbisBitrate(aVorbisQuality: Double): String;
const
  QNBR : array[-1..10] of integer = (45, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 500);
var
  dMultA : double;
  dMultB : double;
  nQualityA : integer;
  nQualityB : integer;
  dEstBitrate : double;
begin
  nQualityA := floor(aVorbisQuality);
  nQualityB := min(nQualityA + 1,10);
  if (aVorbisQuality > 0) then
    dMultB := aVorbisQuality - nQualityA
  else
    dMultB := aVorbisQuality - nQualityA;
    dMultA := 1.0 - dMultB;
    dEstBitrate := (dMultA * QNBR[nQualityA]) + (dMultB * QNBR[nQualityB]);
    Result := ' (~' + FloatToStr(Round(dEstBitrate)) + ')';
end;

/psycosoft-funware
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