Users browsing this thread: 1 Guest(s)
How fawfulthegreat64 extracted SFX from Super Paper Mario(from .samp file)?
#1
Information 
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($sdirNamePATHINFO_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($sdirFile0x04);
 
       $arcFileCount fread($sdirFile4);
 
       $arcIndexOffset fread($sdirFile4);
 
       if(strlen($arcFileCount)!=|| 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 || $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($sdirFile4);
 
           $sdirSize fread($sdirFile4);
 
           fseek($sdirFile8SEEK_CUR);
 
           $InnerExt fread($sdirFile4);
 
           fseek($sdirFile12SEEK_CUR);
 
           if (strlen($sdirOffset)!=|| strlen($sdirSize)!=|| 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($sdirFile0x10);
 
       $sdirOffset fread($sdirFile4);
 
       $sdirSize fread($sdirFile4);
 
       fseek($sdirFile0x28);
 
       $sampOffset fread($sdirFile4);
 
       $sampSize fread($sdirFile4);
 
       if(strlen($sdirOffset)!=|| strlen($sdirSize)!=|| strlen($sampOffset)!=|| 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($sdirFile4SEEK_CUR);
 
       $Offset fread($sdirFile4);
 
       fseek($sdirFile6SEEK_CUR);
 
       $Rate fread($sdirFile2);
 
       $RawSamples fread($sdirFile4);
 
       fseek($sdirFile12SEEK_CUR);
 
       //$LoopStart = fread($sdirFile, 4);
 
       //$LoopEnd = fread($sdirFile, 4);
 
       //$DecDataOffset = fread($sdirFile, 4);
 
       if(strlen($Offset)!=|| strlen($Rate)!=|| 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($sdirFile4SEEK_CUR);
 
   for($i=1$i<=$Entries; ++$i)
 
   {
 
       fseek($sdirFile8SEEK_CUR);
 
       $Coeffs fread($sdirFile32);
 
       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($sampFile16);
 
           $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;
}

?>
Reply
Thanked by:
#2
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.
[Image: OOovP5l.gif]
Reply
Thanked by:
#3
(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.
Reply
Thanked by:


Forum Jump: