ambiera home ambiera home

irrKlang Tutorial: Override File Access (C++)

This example will show how to override file access with irrKlang. This is useful if you want to read sounds from other sources than just files, for example from custom internet streams or an own encypted archive format.

Let's start

Include irrKlang headers and other input/output stuff needed to print and get user input from the console.

#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <irrKlang.h>

using namespace irrklang;

#pragma comment(lib, "irrKlang.lib") // link with irrKlang.dll

To start, we need to implement the class IFileFactory, which irrKlang uses to open files. The interface consists only of one single method named createFileReader(const ik_c8* filename). In this method, we create return our own file access class and return it:

// a class implementing the IFileFactory 
// interface to override irrklang file access
class CMyFileFactory : public irrklang::IFileFactory
{
public:

   //! Opens a file for read access. Simply return 0 if file not found.
   virtual irrklang::IFileReader* createFileReader(const ik_c8* filename)
   {
      printf("MyFileFactory: open file %s\n", filename);

      FILE* file = fopen(filename, "rb");
      if (!file)
         return 0;

      return new CMyReadFile(file, filename);
   }

protected:

To write our own file access methods returned in the method above, we only need to implement the IFileReader interface, which has some standard methods like read(), seek(), getPos() etc. In this example we simply use fopen, fread, fseek etc and print to the console when we are reading or seeking:

// an own implementation if IReadFile to overwrite read access to files 
class CMyReadFile : public irrklang::IFileReader
{
public:

   // constructor, store size of file and filename
   CMyReadFile(FILE* openedFile, const ik_c8* filename)
   {
      File = openedFile;
      strcpy(Filename, filename);

      // get file size
      fseek(File, 0, SEEK_END);
      FileSize = ftell(File);
      fseek(File, 0, SEEK_SET);
   }

   ~CMyReadFile()
   {
      fclose(File);
   }

   //! reads data, returns how much was read
   ik_s32 read(void* buffer, ik_u32 sizeToRead)
   {
      printf("CMyReadFile: read %d bytes\n", sizeToRead);
      return (s32)fread(buffer, 1, sizeToRead, File);
   }

   //! changes position in file, returns true if successful
   bool seek(ik_s32 finalPos, bool relativeMovement)
   {
      printf("CMyReadFile: seek to position %d\n", finalPos);
      return fseek(File, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET) == 0;
   }

   //! returns size of file
   ik_s32 getSize()
   {
      return FileSize;
   }

   //! returns where in the file we are.
   ik_s32 getPos()
   {
      return ftell(File);
   }

   //! returns name of file
   const ik_c8* getFileName()
   {
      return Filename;
   }

   FILE* File;
   char Filename[1024];
   ik_s32 FileSize;

   }; // end class CMyReadFile
   
}; // end class CMyFileFactory

The main work is done, the only thing missing is to start up the sound engine and tell it to use the created FileFactory for file access:

// irrKlang 3D sound engine example 04, 
// demonstrating how to override file access of irrKlang
int main(int argc, const char** argv)
{
   // start the sound engine with default parameters
   ISoundEngine* engine = createIrrKlangDevice();

   if (!engine)
      return 0; // error starting up the engine

Create an instance of the file factory and let irrKlang know about it. irrKlang will drop() the factory itself if it doesn't need it any longer.

   CMyFileFactory* factory = new CMyFileFactory();
			
   engine->addFileFactory(factory);

   factory->drop(); // we don't need it anymore, delete it

To test out the written file access functions now only play some sounds with our overridden file access methods:

   printf("\nDemonstrating file access overriding.\n");
   printf("Press any key to start playing sounds, then press escape to cancel\n");

   getch();

   engine->play2D("../../media/getout.ogg", true);

   while(true) // endless loop until user exits
   {
      // play some wave sound
      engine->play2D("../../media/explosion.wav");
	
      if (getch() == 27)
         break; // user pressed ESCAPE key, cancel
   }

   engine->drop(); // delete engine
   return 0;
} 

That's it.
Download tutorial source and binary (included in the SDK)