The VG Resource
How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)? - Printable Version

+- The VG Resource (https://archive.vg-resource.com)
+-- Forum: The Resources (https://archive.vg-resource.com/forum-109.html)
+--- Forum: The Sounds Resource (https://archive.vg-resource.com/forum-112.html)
+---- Forum: Ripping Help (https://archive.vg-resource.com/forum-116.html)
+---- Thread: How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)? (/thread-26064.html)



How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)? - LeonidJeweller - 10-20-2014

According by this upload of SFX http://www.sounds-resource.com/wii/superpapermario/,i want to ask,how he did that,because one user(Phaze) wrote:
Quote:So in the basics as people figured, there are sound effects in the pmario.samp file located in the TTYD ISO's /sound/proj/ folder. I've confirmed this by importing the pmario.samp file as Raw Data in Audacity. The only thing is that when I've imported the data, there is this awful LOUD, SCREECHY NOISE PERMEATING THE WHOLE FILE SO IT'S NOT USABLE FOR ANYTHING BUT DAMAGING YOUR EARS. On the plus side though, I did noticeably hear Bowser/Mario/Peach's voice clips past the mid point in the noise! Based on other docs I've read, the format might be a custom-ish 4-bit ADPCM format used for other things in the 'cube like streamed audio. Makes sense.
.
But .samp(samples) file is contains in Wii game images!
UPVery Sad I found unpacker script .samp files(by Nisto) here its source code and .php file(PHP):
.php file(at mega.co.nz)
PHP Code:
?php
/*
 *
 * MusyX sample extraction tool   by Nisto
 * Last revision: May 16, 2014
 *
 * Minimum required PHP version: 4.1.0
 *
 */

if($argc!=3)
{
 
   echo 'Usage: php <script> <sound_dir> <format>                          ' . PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo 'script                                                            ' . PHP_EOL;
 
   echo '   ' . $argv[0]                                                     . PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo 'sound_dir                                                         ' . PHP_EOL;
 
   echo '   path to the sound directory                                    ' . PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo 'format                                                            ' . PHP_EOL;
 
   echo '   0 - standard MusyX .sdir format                                ' . PHP_EOL;
 
   echo '   1 - .sdir within a .arc file (e.g. Resident Evil 0)            ' . PHP_EOL;
 
   echo '   2 - .snd format (e.g. Resident Evil)                           ' . PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo 'The script has only been tested with the following GameCube games:' . PHP_EOL;
 
   echo '   * Biohazard (Resident Evil)                                    ' . PHP_EOL;
 
   echo '   * Biohazard 0 (Resident Evil 0)                                ' . PHP_EOL;
 
   echo '   * Paper Mario: The Thousand-Year Door                          ' . PHP_EOL;
 
   echo '   * Star Fox Adventures                                          ' . PHP_EOL;
 
   echo                                                                        PHP_EOL;
 
   echo 'It may or may not work with other games utilizing MusyX.          ' . PHP_EOL;
 
   exit();
}

if(!
is_dir($argv[1]))
{
 
   exit('The directory path specified does not appear to be valid.');
}

if(
$argv[2]!=='0' && $argv[2]!=='1' && $argv[2]!=='2')
{
 
   exit('Invalid format specified.');
}





define('SOUND_DIR', rtrim(realpath($argv[1]), DIRECTORY_SEPARATOR));
define('OUT_DIR', SOUND_DIR . DIRECTORY_SEPARATOR . 'samples');
define('FORMAT', $argv[2]);
define('NULL_64BIT', pack('x8'));
define('HEADER_PAD', pack('x36'));

if((
$Dir = opendir(SOUND_DIR)) === FALSE)
{
 
   exit('ERROR: Could not open input directory! Terminating script.');
}

if(!
is_dir(OUT_DIR) && mkdir(OUT_DIR) === FALSE)
{
 
   exit('ERROR: Could not create output directory! Terminating script.');
}

$sdirExts = array('sdir','sdi','arc','snd');
$Done = array();

while((
$sdirName = readdir($Dir)) !== FALSE)
{
 
   /*
     * skip irrelevant and already-done files
     */
 
   $sdirPath = SOUND_DIR . DIRECTORY_SEPARATOR . $sdirName;
 
   if (!is_file($sdirPath))
 
   {
 
       continue;
 
   }

 
   $Ext = strtolower(pathinfo($sdirName, PATHINFO_EXTENSION));
 
   if (!in_array($Ext, $sdirExts))
 
   {
 
       continue;
 
   }

 
   $Basename = strtolower(basename($sdirName, '.'.$Ext));
 
   if (in_array($Basename, $Done))
 
   {
 
       continue;
 
   }





 
   /*
     * parse files according to the format specified
     * if the extension does not match with the selected format,
     * skip the file
     *
     * because there may be errors before finishing parsing,
     * we need to add to $Done[] individually
     */
 
   if (($sdirFile = fopen($sdirPath, 'rb')) === FALSE)
 
   {
 
       err_skip('Could not open sdir %s for reading.', $sdirName);
 
       continue;
 
   }

 
   if(FORMAT=='0' && ($Ext=='sdir'||$Ext=='sdi'))
 
   {
 
       // standard sdir

 
       $Done[] = $Basename;

 
       $sdirOffset = 0;
 
       $sdirSize = filesize($sdirPath);

 
       $sampPath = SOUND_DIR . DIRECTORY_SEPARATOR . $Basename . '.sam';
 
       if(!file_exists($sampPath) && !file_exists($sampPath .= 'p'))
 
       {
 
           err_skip($sdirFile, 'Could not find the sample file for %s.', $sdirName);
 
           continue;
 
       }
 
       $sampName = basename($sampPath);
 
       $sampOffset = 0;
 
       $sampSize = filesize($sampPath);
 
   }
 
   elseif(FORMAT=='1' && $Ext=='arc')
 
   {
 
       // standard sdir in arc

 
       $Done[] = $Basename;

 
       fseek($sdirFile, 0x04);
 
       $arcFileCount = fread($sdirFile, 4);
 
       $arcIndexOffset = fread($sdirFile, 4);
 
       if(strlen($arcFileCount)!=4 || strlen($arcIndexOffset)!=4)
 
       {
 
           err_skip($sdirFile, 'Failed reading arc header values in %s.', $sdirName);
 
           continue;
 
       }

 
       $arcSize = filesize($sdirPath);
 
       $arcFileCount = unpack('N', $arcFileCount)[1];
 
       $arcIndexOffset = unpack('N', $arcIndexOffset)[1];
 
       if ($arcFileCount < 1 || $arcIndexOffset+($arcFileCount*32) > $arcSize)
 
       {
 
           err_skip($sdirFile, '%s does not appear to be a valid .arc file.', $sdirName);
 
           continue;
 
       }

 
       fseek($sdirFile, $arcIndexOffset);
 
       for($i=1; $i<=$arcFileCount; ++$i)
 
       {
 
           $sdirOffset = fread($sdirFile, 4);
 
           $sdirSize = fread($sdirFile, 4);
 
           fseek($sdirFile, 8, SEEK_CUR);
 
           $InnerExt = fread($sdirFile, 4);
 
           fseek($sdirFile, 12, SEEK_CUR);
 
           if (strlen($sdirOffset)!=4 || strlen($sdirSize)!=4 || strlen($InnerExt)!=4)
 
           {
 
               err_skip($sdirFile, 'Failed reading data from arc file %s.', $sdirName);
 
               continue 2;
 
           }

 
           if ($InnerExt=='sdir')
 
           {
 
               break;
 
           }
 
       }

 
       if($InnerExt!='sdir')
 
       {
 
           err_skip($sdirFile, 'Could not locate sdir file within %s.', $sdirName);
 
           continue;
 
       }

 
       $sdirOffset = unpack('N',$sdirOffset)[1];
 
       $sdirSize = unpack('N',$sdirSize)[1];
 
       if($sdirOffset+$sdirSize > $arcSize)
 
       {
 
           err_skip($sdirFile, 'The sdir table in %s is out of range based on header values.', $sdirName);
 
           continue;
 
       }

 
       $sampPath = SOUND_DIR . DIRECTORY_SEPARATOR . $Basename . '.sam';
 
       if(!file_exists($sampPath) && !file_exists($sampPath .= 'p'))
 
       {
 
           err_skip($sdirFile, 'Could not find the sample file for %s.', $sdirName);
 
           continue;
 
       }
 
       $sampName = basename($sampPath);
 
       $sampOffset = 0;
 
       $sampSize = filesize($sampPath);
 
   }
 
   elseif(FORMAT=='2' && $Ext=='snd')
 
   {
 
       // .snd

 
       $Done[] = $Basename;

 
       $sampFile = $sdirFile;
 
       $sampPath = $sdirPath;
 
       $sampName = $sdirName;

 
       fseek($sdirFile, 0x10);
 
       $sdirOffset = fread($sdirFile, 4);
 
       $sdirSize = fread($sdirFile, 4);
 
       fseek($sdirFile, 0x28);
 
       $sampOffset = fread($sdirFile, 4);
 
       $sampSize = fread($sdirFile, 4);
 
       if(strlen($sdirOffset)!=4 || strlen($sdirSize)!=4 || strlen($sampOffset)!=4 || strlen($sampSize)!=4)
 
       {
 
           err_skip($sdirFile, 'Failed to read snd header values in %s.', $sdirName);
 
           continue;
 
       }

 
       $sndSize = filesize($sdirPath);
 
       $sdirOffset = unpack('N',$sdirOffset)[1];
 
       $sdirSize = unpack('N',$sdirSize)[1];
 
       $sampOffset = unpack('N',$sampOffset)[1];
 
       $sampSize = unpack('N',$sampSize)[1];
 
       if($sdirOffset+$sdirSize > $sndSize)
 
       {
 
           err_skip($sdirFile, 'The sdir table in %s is out of range based on header values.', $sdirName);
 
           continue;
 
       }

 
       if($sampOffset+$sampSize > $sndSize)
 
       {
 
           err_skip($sdirFile, 'The sample chunk in %s is out of range based on header values.', $sdirName);
 
           continue;
 
       }
 
   }
 
   else
    
{
 
       continue;
 
   }





 
   /*
     * get offset, sample rate, raw sample count, coefficients
     * (and maybe, eventually, some other data)
     *
     * 4  - 0xFF FF FF FF (end of block)
     * 32 - block 1 entry size
     * 40 - block 2 entry size (that I've ever seen..)
     */
 
   $SampleArr = array();
 
   $Entries = ($sdirSize-4) / (32+40);
 
   if(($sdirSize-4) % $Entries)
 
   {
 
       err_skip($sdirFile, 'Unexpected entry size in sdir table 2 in %s.', $sdirName);
 
       continue;
 
   }

 
   fseek($sdirFile, $sdirOffset);
 
   for($i=1; $i<=$Entries; ++$i)
 
   {
 
       fseek($sdirFile, 4, SEEK_CUR);
 
       $Offset = fread($sdirFile, 4);
 
       fseek($sdirFile, 6, SEEK_CUR);
 
       $Rate = fread($sdirFile, 2);
 
       $RawSamples = fread($sdirFile, 4);
 
       fseek($sdirFile, 12, SEEK_CUR);
 
       //$LoopStart = fread($sdirFile, 4);
 
       //$LoopEnd = fread($sdirFile, 4);
 
       //$DecDataOffset = fread($sdirFile, 4);
 
       if(strlen($Offset)!=4 || strlen($Rate)!=2 || strlen($RawSamples)!=4)
 
       {
 
           err_skip($sdirFile, 'Failed to read attributes from sdir table in %s.', $sdirName);
 
           continue 2;
 
       }

 
       $SampleArr[$i]['start_offset']    = $sampOffset + unpack('N',$Offset)[1];
 
       $SampleArr[$i]['rate']            = unpack('n',$Rate)[1];
 
       $SampleArr[$i]['raw_samples']     = unpack('N',$RawSamples)[1];
 
       //$SampleArr[$i]['loop_start']      = unpack('N',$LoopStart)[1];
 
       //$SampleArr[$i]['loop_end']        = unpack('N',$LoopEnd)[1];
 
       //$SampleArr[$i]['dec_data_offset'] = unpack('N',$DecDataOffset)[1];

 
       if ($i>1)
 
       {
 
           $SampleArr[$i-1]['end_offset'] = $SampleArr[$i]['start_offset'];
 
       }

 
       if ($i==$Entries)
 
       {
 
           $SampleArr[$i]['end_offset'] = $sampOffset + $sampSize;
 
       }
 
   }

 
   fseek($sdirFile, 4, SEEK_CUR);
 
   for($i=1; $i<=$Entries; ++$i)
 
   {
 
       fseek($sdirFile, 8, SEEK_CUR);
 
       $Coeffs = fread($sdirFile, 32);
 
       if(strlen($Coeffs)!=32)
 
       {
 
           err_skip($sdirFile, 'Failed to read sample %d coefficients from the sdir table in %s.', $n, $Filename);
 
           continue 2;
 
       }
 
       $SampleArr[$i]['coeffs'] = $Coeffs;
 
   }




 
   /*
     * get sample data, make header, and output to DSP files
     */
 
   echo 'Extracting samples from ' . $sampName . '... ';

 
   if($sdirPath != $sampPath)
 
   {
 
       fclose($sdirFile);

 
       if(($sampFile = fopen($sampPath,'rb')) === FALSE)
 
       {
 
           err_skip('Could not open file for reading.');
 
           continue;
 
       }
 
   }

 
   $dspDirPath = OUT_DIR . DIRECTORY_SEPARATOR . $Basename;
 
   if(!is_dir($dspDirPath) && mkdir($dspDirPath) === FALSE)
 
   {
 
       err_skip($sampFile, 'Could not create DSP output directory.');
 
       continue;
 
   }

 
   fseek($sampFile, $sampOffset);
 
   foreach($SampleArr as $n => $Sample)
 
   {
 
       if($Sample['start_offset'] >= $sampSize)
 
       {
 
           err_skip($sampFile, 'Sample %d is out of range based on the offsets from the sdir table.', $n);
 
           continue 2;
 
       }

 
       $SampleData = '';
 
       $p = ftell($sampFile);
 
       while ($p < $Sample['end_offset'])
 
       {
 
           $Bytes = fread($sampFile, 16);
 
           $p = ftell($sampFile);
 
           if($p < $sampSize && strlen($Bytes)!=16)
 
           {
 
               err_skip($sampFile, 'Failed to read sample data at 0x%x.', ftell($sampFile));
 
               continue 3;
 
           }
 
           $SampleData .= $Bytes;
 
       }

 
       // fixes some (not all) files that vgmstream won't play
 
       if(substr($SampleData,0,8)!=NULL_64BIT)
 
       {
 
           $SampleData = NULL_64BIT . $SampleData;
 
       }
 
       $SampleDataLen = strlen($SampleData);

 
       $RawSamples = $Sample['raw_samples'];
 
       $Nibbles    = $SampleDataLen * 2;
 
       $Rate       = $Sample['rate'];
 
       $LoopFlag   = 0;//($Sample['loop_start'] || $Sample['loop_end']) ? 1 : 0;
 
       $LoopStart  = 2;//$Sample['loop_start'];
 
       $LoopEnd    = 0;//$Sample['loop_end'];
 
       $Coeffs     = $Sample['coeffs'];

 
       $Header = pack('N',$RawSamples);  // 0x00 raw samples
 
       $Header.= pack('N',$Nibbles);     // 0x04 nibbles
 
       $Header.= pack('N',$Rate);        // 0x08 sample rate

 
       $Header.= pack('n',$LoopFlag);    // 0x0C loop flag
 
       $Header.= pack('n',00000000);     // 0x0E format (always zero - ADPCM)
 
       $Header.= pack('N',$LoopStart);   // 0x10 loop start address (in nibbles)
 
       $Header.= pack('N',$LoopEnd);     // 0x14 loop end address (in nibbles)
 
       $Header.= pack('N',00000002);     // 0x18 initial offset value (in nibbles)
 
       $Header.= $Coeffs;                // 0x1C

 
       $Header.= HEADER_PAD;

 
       //$Header.= pack('n',...);        // 0x3C gain
 
       //$Header.= pack('n',...);        // 0x3E predictor/scale
 
       //$Header.= pack('n',...);        // 0x40 sample history
 
       //$Header.= pack('n',...);        // 0x42 sample history

 
       //$Header.= pack('n',...);        // 0x44 predictor/scale for loop context
 
       //$Header.= pack('n',...);        // 0x46 sample history for loop context
 
       //$Header.= pack('n',...);        // 0x48 sample history for loop context

 
       //$Header.= pack('x22');          // 0x4A pad (reserved)

 
       $dspName = str_pad($n,2,'0',STR_PAD_LEFT) . '.dsp';
 
       $dspPath = $dspDirPath . DIRECTORY_SEPARATOR . $dspName;
 
       if(($dspFile = fopen($dspPath, 'wb')) === FALSE)
 
       {
 
           err_skip($sampFile, 'Could not open sample %d output file for writing.', $n);
 
           continue 2;
 
       }

 
       if(fwrite($dspFile, $Header.$SampleData) != 0x60+$SampleDataLen)
 
       {
 
           err_skip($sampFile, $dspFile, 'Failed writing data to %s.', $dspName);
 
           continue 2;
 
       }

 
       fclose($dspFile);
 
   }

 
   fclose($sampFile);

 
   echo 'Done.' . PHP_EOL;
}

echo 
'No more files to process.' . PHP_EOL;

closedir($Dir);

function 
err_skip()
{
 
   $Args = func_get_args();
 
   $Arg1 = array_shift($Args);

 
   while (is_resource($Arg1) && get_resource_type($Arg1)=='stream')
 
   {
 
       fclose($Arg1);
 
       $Arg1 = array_shift($Args);
 
   }

 
   $Err = vsprintf($Arg1, $Args);
 
   echo 'ERROR: ' . $Err . ' Skipping the input file.' . PHP_EOL;
}

?>



RE: How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)? - Fawfulthegreat64 - 10-21-2014

I got SPM's sound effects from a BRSAR file by opening it in BrawlBox. I was unable to get TTYD's sound effects because it uses a different file format, so I don't know what to say really. I didn't get them from a .samp file anyway.


RE: How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)? - LeonidJeweller - 10-22-2014

(10-21-2014, 06:49 PM)fawfulthegreat64 Wrote: I got SPM's sound effects from a BRSAR file by opening it in BrawlBox. I was unable to get TTYD's sound effects because it uses a different file format, so I don't know what to say really. I didn't get them from a .samp file anyway.
Thanks ,but i already found way to unpack from TTYD.