[vorbis-dev] Getting a GUI to work with Vorbis code

Paul Newton Paul.Newton at sli-institute.ac.uk
Tue Aug 6 08:03:28 PDT 2002



I am trying to create a Graphical User Interface for a Vorbis Player under
MS Visual C++ 6.0

I was initially trting to use the code from decoder_example.c but I keep
getting linker errors.

I have set up my project as told to by James Boer on this mailing list.

This is as follows:

This document was prepared from an email received from James Boer on the Ogg
Vorbis mailing list.  It gives a walkthrough on how to compile an example
file supplied with the Ogg Vorbis source code.  The method will be needed
when code is developed which relies on the Ogg Vorbis source code.

1.	The files extracted from the vorbis-sdk-1.0rc3.zip
<http://www.vorbis.com/files/rc3/windows/vorbis-sdk-1.0rc3.zip> should be
stored in a known location so that Visual C++ can locate the files.  For the
purposes of this document it is assumed that they are installed at
c:\vorbis_sdk

2.	To specify the locations of these files in Visual C++  goto Tools ->
Options and select the directories tab.  Select Include Files from the Show
directories for: drop down menu.  Add an entry which points to
c:\vorbis_sdk\include.  Change to Library Files and add an entry which
points to c:\vorbis_sdk\lib.

3.	Create a new Visual C++ Project and workspace.  Goto File->New and
select Win32 Console Application.  Give this an appropriate name and
location.  When prompted ask for an Empty Project.

4.	Copy the file vorbisfile_example.c to the new project directory.
Select Project->Add to Project->Add Files....  Select vorbisfile_example.c
from the list.

5.	The program must now be linked to the vorbis libraries.  The Library
types are given below:

                Ogg.lib			Base library used for ogg projects
                Vorbis.lib			Low-level Vorbis decoding
library
                Vorbisenc.lib		Low-level Vorbis encoding library
                Vorbisfile.lib		High-level Vorbis file reading
library

                The static versions of the libraries can be used instead of
the dll's.  This is achieved by adding _static to the name of the library
file.  The debug versions have a _d appended to their name.

                To add the libraries to the project:Select
Project->Settings.  Click the Link tab.  Under the Object/library modules
section append ogg_d.lib, vorbis_d.lib and vorbisfile_d.lib to the end of
the list.  In the Settings For: dropdown menu select Win32 Release.  In the
same way as previously add ogg.lib, vorbis.lib and vorbisfile.lib to the end
of the list.  Add _static before .lib for Release version if using static
libraries.

                If compilation with static libraries is required then the
following should also be carried out.  Select Project->Settings and select
the C/C++ tab.  Select Code Generation from the category list.  From the Use
run-time library: dropdown list select Debug Multithreaded DLL for the Debug
Project, and Multithreaded DLL for Release.
6.	Copy the Vorbis dll's to the project directory.  This is not
necessary if the project was compiled with static libraries.

7.   Now Build the project.

<p>For my GUI I created a MFCAppWizard(exe) Project.  I then created some
buttons.  Initially I just want te press of a button to start the
decoder_example code.

My code looks like this:

<p><p>// GUIDlg.cpp : implementation file
//

#include "stdafx.h"
#include "GUI.h"
#include "GUIDlg.h"

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

<p>//**************************************************************************
**
//Ogg Vorbis Stuff

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vorbis/codec.h>

/* NB vorbisfile.h not included - GK */

#ifdef _WIN32 /* We need the following two to set stdin/stdout to binary */
#include <io.h>
#include <fcntl.h>
#endif

#if defined(macintosh) && defined(__MWERKS__)
#include <console.h>      /* CodeWarrior's Mac "command-line" support */
#endif

ogg_int16_t convbuffer[4096]; /* take 8k out of the data segment, not the
stack */
int convsize=4096;

<p>//**************************************************************************
*

<p><p>////////////////////////////////////////////////////////////////////////////
/
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
        CAboutDlg();

// Dialog Data
        //{{AFX_DATA(CAboutDlg)
        enum { IDD = IDD_ABOUTBOX };
        //}}AFX_DATA

        // ClassWizard generated virtual function overrides
        //{{AFX_VIRTUAL(CAboutDlg)
        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV
support
        //}}AFX_VIRTUAL

// Implementation
protected:
        //{{AFX_MSG(CAboutDlg)
        //}}AFX_MSG
        DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
        //{{AFX_DATA_INIT(CAboutDlg)
        //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialog::DoDataExchange(pDX);
        //{{AFX_DATA_MAP(CAboutDlg)
        //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
        //{{AFX_MSG_MAP(CAboutDlg)
                // No message handlers
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////////////////
/
// CGUIDlg dialog

CGUIDlg::CGUIDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CGUIDlg::IDD, pParent)
{
        //{{AFX_DATA_INIT(CGUIDlg)
                // NOTE: the ClassWizard will add member initialization here
        //}}AFX_DATA_INIT
        // Note that LoadIcon does not require a subsequent DestroyIcon in
Win32
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CGUIDlg::DoDataExchange(CDataExchange* pDX)
{
        CDialog::DoDataExchange(pDX);
        //{{AFX_DATA_MAP(CGUIDlg)
                // NOTE: the ClassWizard will add DDX and DDV calls here
        //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CGUIDlg, CDialog)
        //{{AFX_MSG_MAP(CGUIDlg)
        ON_WM_SYSCOMMAND()
        ON_WM_DESTROY()
        ON_WM_PAINT()
        ON_WM_QUERYDRAGICON()
        ON_BN_CLICKED(IDC_PLAY, OnPlay)
        //}}AFX_MSG_MAP
END_MESSAGE_MAP()

////////////////////////////////////////////////////////////////////////////
/
// CGUIDlg message handlers

BOOL CGUIDlg::OnInitDialog()
{
        CDialog::OnInitDialog();

        // Add "About..." menu item to system menu.

        // IDM_ABOUTBOX must be in the system command range.
        ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
        ASSERT(IDM_ABOUTBOX < 0xF000);

        CMenu* pSysMenu = GetSystemMenu(FALSE);
        if (pSysMenu != NULL)
        {
                CString strAboutMenu;
                strAboutMenu.LoadString(IDS_ABOUTBOX);
                if (!strAboutMenu.IsEmpty())
                {
                        pSysMenu->AppendMenu(MF_SEPARATOR);
                        pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,
strAboutMenu);
                }
        }

        // Set the icon for this dialog.  The framework does this
automatically
        //  when the application's main window is not a dialog
        SetIcon(m_hIcon, TRUE);			// Set big icon
        SetIcon(m_hIcon, FALSE);		// Set small icon
        
        // TODO: Add extra initialization here
        
        return TRUE;  // return TRUE  unless you set the focus to a control
}

void CGUIDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
        if ((nID & 0xFFF0) == IDM_ABOUTBOX)
        {
                CAboutDlg dlgAbout;
                dlgAbout.DoModal();
        }
        else
        {
                CDialog::OnSysCommand(nID, lParam);
        }
}

void CGUIDlg::OnDestroy()
{
        WinHelp(0L, HELP_QUIT);
        CDialog::OnDestroy();
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CGUIDlg::OnPaint() 
{
        if (IsIconic())
        {
                CPaintDC dc(this); // device context for painting

                SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

                // Center icon in client rectangle
                int cxIcon = GetSystemMetrics(SM_CXICON);
                int cyIcon = GetSystemMetrics(SM_CYICON);
                CRect rect;
                GetClientRect(&rect);
                int x = (rect.Width() - cxIcon + 1) / 2;
                int y = (rect.Height() - cyIcon + 1) / 2;

                // Draw the icon
                dc.DrawIcon(x, y, m_hIcon);
        }
        else
        {
                CDialog::OnPaint();
        }
}

// The system calls this to obtain the cursor to display while the user
drags
//  the minimized window.
HCURSOR CGUIDlg::OnQueryDragIcon()
{
        return (HCURSOR) m_hIcon;
}

void CGUIDlg::OnPlay() 
{
  ogg_sync_state   oy; /* sync and verify incoming physical bitstream */
  ogg_stream_state os; /* take physical pages, weld into a logical
                          stream of packets */
  ogg_page         og; /* one Ogg bitstream page.  Vorbis packets are inside
*/
  ogg_packet       op; /* one raw packet of data for decode */
  
  vorbis_info      vi; /* struct that stores all the static vorbis bitstream
                          settings */
  vorbis_comment   vc; /* struct that stores all the bitstream user comments
*/
  vorbis_dsp_state vd; /* central working state for the packet->PCM decoder
*/
  vorbis_block     vb; /* local working space for packet->PCM decode */
  
  char *buffer;
  int  bytes;

  /* Read from file : GK */

  FILE * myFile = fopen("h:/Project/Downloads/Ogg/keoki_passiton.ogg","rb");

  FILE * outputFile = fopen("h:/Project/Visual C++/output.txt", "w");

  fprintf(outputFile, "File read OK.\n");

  /* end modification : GK */
  
#ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows.
*/
  /* Beware the evil ifdef. We avoid these where we can, but this one we 
     cannot. Don't add any more, you'll probably go to hell if you do. */
  _setmode( _fileno( stdin ), _O_BINARY );
  _setmode( _fileno( stdout ), _O_BINARY );
#endif

#if defined(macintosh) && defined(__MWERKS__)
  {
    int argc;
    char **argv;
    argc=ccommand(&argv); /* get a "command line" from the Mac user */
                     /* this also lets the user set stdin and stdout */
  }
#endif

  /********** Decode setup ************/

  ogg_sync_init(&oy); /* Now we can read pages */
  
  while(1){ /* we repeat if the bitstream is chained */
    int eos=0;
    int i;

    /* grab some data at the head of the stream.  We want the first page
       (which is guaranteed to be small and only contain the Vorbis
       stream initial header) We need the first page to get the stream
       serialno. */

    /* submit a 4k block to libvorbis' Ogg layer */
    buffer=ogg_sync_buffer(&oy,4096);
        /* changed from stdin to myFile in next line - GK*/
    bytes=fread(buffer,1,4096,myFile);
        /* added the following line - GK */
        printf("%d bytes read successfully\n",bytes);
    ogg_sync_wrote(&oy,bytes);
    /* Get the first page. */
    if(ogg_sync_pageout(&oy,&og)!=1){
      /* have we simply run out of data?  If so, we're done. */
      if(bytes<4096)break;
      
      /* error case.  Must not be Vorbis data */
      fprintf(outputFile,"Input does not appear to be an Ogg bitstream.\n");
      exit(1);
    }
  
    /* Get the serial number and set up the rest of decode. */
    /* serialno first; use it to set up a logical stream */
    ogg_stream_init(&os,ogg_page_serialno(&og));
    
    /* extract the initial header from the first page and verify that the
       Ogg bitstream is in fact Vorbis data */
    
    /* I handle the initial header first instead of just having the code
       read all three Vorbis headers at once because reading the initial
       header is an easy way to identify a Vorbis bitstream and it's
       useful to see that functionality seperated out. */
    
    vorbis_info_init(&vi);
    vorbis_comment_init(&vc);
    if(ogg_stream_pagein(&os,&og)<0){ 
      /* error; stream version mismatch perhaps */
      fprintf(outputFile,"Error reading first page of Ogg bitstream
data.\n");
      exit(1);
    }
    
    if(ogg_stream_packetout(&os,&op)!=1){ 
      /* no page? must not be vorbis */
      fprintf(outputFile,"Error reading initial header packet.\n");
      exit(1);
    }
    
    if(vorbis_synthesis_headerin(&vi,&vc,&op)<0){ 
      /* error case; not a vorbis header */
      fprintf(outputFile,"This Ogg bitstream does not contain Vorbis "
              "audio data.\n");
      exit(1);
    }
    printf("We're sure we're Vorbis.\n");
    /* At this point, we're sure we're Vorbis.  We've set up the logical
       (Ogg) bitstream decoder.  Get the comment and codebook headers and
       set up the Vorbis decoder */
    
    /* The next two packets in order are the comment and codebook headers.
       They're likely large and may span multiple pages.  Thus we reead
       and submit data until we get our two pacakets, watching that no
       pages are missing.  If a page is missing, error out; losing a
       header page is the only place where missing data is fatal. */
    
    i=0;
    while(i<2){
      while(i<2){
        int result=ogg_sync_pageout(&oy,&og);
        if(result==0)break; /* Need more data */
        /* Don't complain about missing or corrupt data yet.  We'll
           catch it at the packet output phase */
        if(result==1){
          ogg_stream_pagein(&os,&og); /* we can ignore any errors here
                                         as they'll also become apparent
                                         at packetout */
          while(i<2){
            result=ogg_stream_packetout(&os,&op);
            if(result==0)break;
            if(result<0){
              /* Uh oh; data at some point was corrupted or missing!
                 We can't tolerate that in a header.  Die. */
              fprintf(outputFile,"Corrupt secondary header.  Exiting.\n");
              exit(1);
            }
            vorbis_synthesis_headerin(&vi,&vc,&op);
            i++;
          }
        }
      }
      /* no harm in not checking before adding more */
      buffer=ogg_sync_buffer(&oy,4096);
          /* changed from stdin to myFile in next line - GK */
      bytes=fread(buffer,1,4096,myFile);
      if(bytes==0 && i<2){
        fprintf(outputFile,"End of file before finding all Vorbis
headers!\n");
        exit(1);
      }
      ogg_sync_wrote(&oy,bytes);
    }
    
    /* Throw the comments plus a few lines about the bitstream we're
       decoding */
    {
      char **ptr=vc.user_comments;
      while(*ptr){
        fprintf(outputFile,"%s\n",*ptr);
        ++ptr;
      }
      fprintf(outputFile,"\nBitstream is %d channel,
%ldHz\n",vi.channels,vi.rate);
      fprintf(outputFile,"Encoded by: %s\n\n",vc.vendor);
    }
    
    convsize=4096/vi.channels;

    /* OK, got and parsed all three headers. Initialize the Vorbis
       packet->PCM decoder. */
    vorbis_synthesis_init(&vd,&vi); /* central decode state */
    vorbis_block_init(&vd,&vb);     /* local state for most of the decode
                                       so multiple block decodes can
                                       proceed in parallel.  We could init
                                       multiple vorbis_block structures
                                       for vd here */
    
    /* The rest is just a straight decode loop until end of stream */
    while(!eos){
      while(!eos){
        int result=ogg_sync_pageout(&oy,&og);
        if(result==0)break; /* need more data */
        if(result<0){ /* missing or corrupt data at this page position */
          fprintf(outputFile,"Corrupt or missing data in bitstream; "
                  "continuing...\n");
        }else{
          ogg_stream_pagein(&os,&og); /* can safely ignore errors at
                                         this point */
          while(1){
            result=ogg_stream_packetout(&os,&op);

            if(result==0)break; /* need more data */
            if(result<0){ /* missing or corrupt data at this page position
*/
              /* no reason to complain; already complained above */
            }else{
              /* we have a packet.  Decode it */
              float **pcm;
              int samples;
              
              if(vorbis_synthesis(&vb,&op)==0) /* test for success! */
                vorbis_synthesis_blockin(&vd,&vb);
              /* 
                 
              **pcm is a multichannel float vector.  In stereo, for
              example, pcm[0] is left, and pcm[1] is right.  samples is
              the size of each channel.  Convert the float values
              (-1.<=range<=1.) to whatever PCM format and write it out */
              
              while((samples=vorbis_synthesis_pcmout(&vd,&pcm))>0){
                int j;
                int clipflag=0;
                int bout=(samples<convsize?samples:convsize);
                
                /* convert floats to 16 bit signed ints (host order) and
                   interleave */
                for(i=0;i<vi.channels;i++){
                  ogg_int16_t *ptr=convbuffer+i;
                  float  *mono=pcm[i];
                  for(j=0;j<bout;j++){
#if 1
                    int val=mono[j]*32767.f;
#else /* optional dither */
                    int val=mono[j]*32767.f+drand48()-0.5f;
#endif
                    /* might as well guard against clipping */
                    if(val>32767){
                      val=32767;
                      clipflag=1;
                    }
                    if(val<-32768){
                      val=-32768;
                      clipflag=1;
                    }
                    *ptr=val;
                    ptr+=vi.channels;
                  }
                }
                
                if(clipflag)
                  fprintf(outputFile,"Clipping in frame
%ld\n",(long)(vd.sequence));
                
        /* commented out next line - GK */	
        //	fwrite(convbuffer,2*vi.channels,bout,stdout);
                
                vorbis_synthesis_read(&vd,bout); /* tell libvorbis how
                                                   many samples we
                                                   actually consumed */
              }	    
            }
          }
          if(ogg_page_eos(&og))eos=1;
        }
      }
      if(!eos){
        buffer=ogg_sync_buffer(&oy,4096);
        /* changed from stdin to myFile in next line - GK */
        bytes=fread(buffer,1,4096,myFile);
        ogg_sync_wrote(&oy,bytes);
        if(bytes==0)eos=1;
      }
    }
    
    /* clean up this logical bitstream; before exit we see if we're
       followed by another [chained] */

    ogg_stream_clear(&os);
  
    /* ogg_page and ogg_packet structs always point to storage in
       libvorbis.  They're never freed or manipulated directly */
    
    vorbis_block_clear(&vb);
    vorbis_dsp_clear(&vd);
        vorbis_comment_clear(&vc);
    vorbis_info_clear(&vi);  /* must be called last */
  }

  /* OK, clean up the framer */
  ogg_sync_clear(&oy);
  
  fprintf(outputFile,"Done.\n");
        // TODO: Add your control notification handler code here
        
}

<p>I changed the input from stdin to a file.  When I build the project I get

--------------------Configuration: GUI - Win32 Debug--------------------
Linking...
LINK : fatal error LNK1104: cannot open file "ogg_d.lib"
Error executing link.exe.

GUI.exe - 1 error(s), 0 warning(s)

Can anybody explain why this is?

Thanks in advance
Paul

<p><p><p><p><p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'vorbis-dev-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the Vorbis-dev mailing list