home *** CD-ROM | disk | FTP | other *** search
- #include "stdafx.h"
- #include "FrotzCE.h"
- #include "FrotzCESnd.h"
- #include "FrotzCEIO.h"
-
- #include <string.h>
-
- extern "C"
- {
- #include "Frotz/Frotz.h"
- }
-
- // Constructor
- CFrotzCESnd::CFrotzCESnd()
- {
- // Initialise
- m_pachSampleData = NULL;
- m_nCurrentSample = 0;
- m_bPlayingSound = FALSE;
- memset( &m_sHeader, 0, sizeof( m_sHeader ) );
- }
-
- /*
- * Beep
- *
- * Play a beep sound. Ideally, the sound should be high- (number == 1)
- * or low-pitched (nnumber == 2).
- *
- */
-
- void CFrotzCESnd::Beep( int nNumber )
- {
- if( nNumber == 2 )
- MessageBeep( MB_OK );
- else
- MessageBeep( MB_ICONASTERISK );
- }
-
- /*
- * LoadSample
- *
- * Load the given sample from the disk.
- *
- */
-
- BOOL CFrotzCESnd::LoadSample( int nNumber )
- {
- // Loaded sample already?
- if (m_nCurrentSample == nNumber)
- return;
-
- // Find extension
- int nPos;
- for (nPos = strlen( FROTZCEAPP->m_achStoryFile ) - 1;
- nPos >= 0 && FROTZCEAPP->m_achStoryFile[nPos] != '.'; nPos--);
-
- // Get length of base sample file name
- int nStubLen = strlen (FROTZCEAPP->m_achStoryFile ) - nPos;
- if (nStubLen > 6) nStubLen = 6;
-
- // Generate sample file name
- CString strSampleName;
- int nDefDirLen = FROTZCEAPP->m_strDefaultDir.GetLength();
- strSampleName.Format( TEXT( "%.*s\\Sound\\%.*s%02d.snd" ),
- nDefDirLen, FROTZCEAPP->m_achStoryFile, nStubLen,
- &FROTZCEAPP->m_achStoryFile[nDefDirLen+1] );
-
- // Open sample file
- CFile cSampleFile;
- if (cSampleFile.Open( strSampleName, CFile::modeRead ))
- {
- UINT nFileLen;
- BYTE nLoByte, nHiByte;
-
- // Find out how long the file is for error checking later
- cSampleFile.SeekToEnd();
- nFileLen = cSampleFile.GetPosition();
- cSampleFile.SeekToBegin();
-
- // If it's shorter than this, it has to be corrupt (minimum size of sound header)
- if( nFileLen <= MIN_HEADER_SIZE )
- {
- CString strError = TEXT( "SoundFile: " );
-
- // Display error
- strError += strSampleName;
- strError += TEXT( "\nSound file too short!" );
- AfxMessageBox( strError );
- cSampleFile.Close();
- return FALSE;
- }
- // Load header
- // MSB is first, LSB is second
- cSampleFile.Read( &nHiByte, 1 );
- cSampleFile.Read( &nLoByte, 1 );
- m_sHeader.nPrefix = (nHiByte << 8) + nLoByte;
-
- // Valid length?
- if( m_sHeader.nPrefix > nFileLen )
- {
- CString strError = TEXT( "SoundFile: " );
-
- // Display error
- strError += strSampleName;
- strError += TEXT( "\nSound file too short!" );
- AfxMessageBox( strError );
- cSampleFile.Close();
- return FALSE;
- }
-
- // Read sound info
- cSampleFile.Read( &m_sHeader.nRepeats, 1 );
- cSampleFile.Read( &m_sHeader.nBaseNote, 1 );
- cSampleFile.Read( &nHiByte, 1 );
- cSampleFile.Read( &nLoByte, 1 );
- m_sHeader.nFrequency= (nHiByte << 8) + nLoByte;
-
- // Skip the unused two bytes
- cSampleFile.Read( &nHiByte, 1 );
- cSampleFile.Read( &nHiByte, 1 );
-
- // Read sample infp
- cSampleFile.Read( &nHiByte, 1 );
- cSampleFile.Read( &nLoByte, 1 );
- m_sHeader.nLength = ( nHiByte << 8 ) + nLoByte;
-
- // Allocate memory for sample data
- if ((m_pachSampleData = (char *) ::LocalAlloc( LPTR, m_sHeader.nLength)) != NULL)
- {
- // Read sample data
- if( cSampleFile.Read( m_pachSampleData, m_sHeader.nLength ) != m_sHeader.nLength )
- {
- CString strError = TEXT( "SoundFile: " );
-
- // Display error
- strError += strSampleName;
- strError += TEXT( "\nError reading sound data from file!" );
- AfxMessageBox( strError );
- cSampleFile.Close();
- return FALSE;
- }
-
- // Store sample number
- m_nCurrentSample = nNumber;
- }
- else
- {
- CString strError = TEXT( "SoundFile: " );
-
- // Display error
- strError += strSampleName;
- strError += TEXT( "\nNot enough memory for sample!" );
- AfxMessageBox( strError );
- cSampleFile.Close();
- return FALSE;
- }
-
- // Close sample file
- cSampleFile.Close();
-
- return TRUE;
- }
- else
- {
- CString strError = TEXT( "SoundFile: " );
-
- // Display error
- strError += strSampleName;
- strError += TEXT( "\nCould not open sample file!" );
- AfxMessageBox( strError );
- return FALSE;
- }
- }
-
- /*
- * StartSample
- *
- * Play the given sample at the given volume (ranging from 1 to 8 and
- * 255 meaning a default volume). The sound is played once or several
- * times in the background (255 meaning forever). In Z-code 3, the
- * repeats value is always 0 and the number of repeats is taken from
- * the sound file itself. The end_of_sound function is called as soon
- * as the sound finishes.
- *
- */
-
- void CFrotzCESnd::StartSample( int nNumber, int nVolume, int nRepeats )
- {
- WAVEFORMAT EX sWaveFormat;
- WAVEHDR sWaveHdr;
-
- // Stop sample from playing
- StopSample();
-
- // Try to load specified sample
- if (!LoadSample( nNumber )) return;
-
- // Clear wave headers
- memset( &sWaveFormat, 0, sizeof( WAVEFORMATEX ) );
- memset( &sWaveHdr, 0, sizeof( WAVEHDR ) );
-
- // Set this up for PCM, 1 channel, 8 bits unsigned samples
- sWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
- sWaveFormat.nChannels = 1;
- sWaveFormat.nSamplesPerSec = m_sHeader.nFrequency;
- sWaveFormat.nAvgBytesPerSec = m_sHeader.nFrequency;
- sWaveFormat.nBlockAlign = 1;
- sWaveFormat.wBitsPerSample = 8;
- sWaveFormat.cbSize = 0;
-
- // Set up wave header
- sWaveHdr.lpData = (LPSTR) m_pachSampleData;
- sWaveHdr.dwBufferLength = m_sHeader.nLength;
- sWaveHdr.dwLoops = m_sHeader.nRepeats;
- if (sWaveHdr.dwLoops == 0) sWaveHdr.dwLoops = 255;
- if (h_version >= V5) sWaveHdr.dwLoops = nRepeats;
- sWaveHdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
-
- // Play sound
- m_bPlayingSound = sndPlaySound( sWaveHdr, SND_ASYNC | SND_MEMORY );
- }
-
- /*
- * StopSample
- *
- * Turn off the current sample.
- *
- */
-
- void CFrotzCESnd::StopSample (void)
- {
- // Playing sound?
- if (m_bPlayingSound)
- {
- // Stop sound
- sndPlaySound( NULL, 0 );
- m_bPlayingSound = FALSE;
- }
- }
-
- /*
- * ResetSound()
- *
- * Free resources allocated for playing samples.
- *
- */
-
- void CFrotzCESnd::ResetSound()
- {
- // Stop playing sample
- StopSample();
-
- // Free buffer
- if (m_pchSampleData) delete m_pchSampleData;
- m_pchSampleData = NULL;
-
- m_nCurrentSample = 0;
- }
-
- // Destructor
- CFrotzCESnd::~CFrotzCESnd()
- {
- // Clean up
- ResetSound();
- }