WAV to Zoom 707II guitar effect sample converter.

For issues with communication ports, protocols, etc.
Post Reply
D.J.Peters
Posts: 8575
Joined: May 28, 2005 3:28
Contact:

WAV to Zoom 707II guitar effect sample converter.

Post by D.J.Peters »

I got a vintage Zoom 707II guitar effect pedal in absolute perfect shape for only 20€ with smart card slot for recording and playback of sample/loops and effect patch storage. click to enlarge:
Image
First I opened from the smart media card a fresh recorded sample loop with an hex editor
and found out it's a simple Zoom TEXT header and a 32bit fixed Zoom ID aligned to 512 bytes (filled with zeros)

Then I loaded with the open source editor 'Audacity' the the Zoom sample *.BIN file as raw mono 16bit 44.1KHz audio file as big endian (skiping the first 512 bytes header)
While playback it was to fast so I read the *.pdf manual and found out the sample engine sampled with 31.25KHz ! (not bad in the 90th)
In Audacity you can change the playback rate of an audio track to 31250 Hz and the playback speed was OK now.

The problem are you can import WAV, MP3, RAW etc. files in Audacity but you can't export it as raw file with new sample rate nor in big endian !

Long story short I wrote this tiny Mono/Stero 8/16 bit '*.WAV' file converter to create Zoom 16 bit Mono 31.25KHz *.BIN files.
(the wav import is the same stuff used in FBSound)

I import any stuff in Audacity and save it as "SAMPLE00.wav ... SAMPLE99.wav"
then I drag and drob this created wav files over the tool wav2sample.exe the result are "SAMPLE00.BIN ... SAMPLE99.bin"
(other file names are ignored from smart media card)

On linux I must give a filename manualy e.g.: /wav2sample sample12.wav

There is one tiny pitfall a "1" on red seven segment display in the sampler menu means the "sample00.bin" a "2" "sample01.bin" ...

Joshy

file: "wav2sample.bas"

Code: Select all

#ifndef NULL
 #define NULL cptr(any ptr,0)
#endif

const _WAVE_FORMAT_PCM     as short = 1
const _PCM_WAVEFORMAT_SIZE as long  = 16
const _PCM_FMT_SIZE        as long  = 16
const _PCM_FILE_HDR_SIZE            = 44

type VCCs as ulong
const as VCCs _RIFF = &H46464952 ' 'RIFF'
const as VCCs _WAVE = &H45564157 ' 'WAVE'
const as VCCs _fmt  = &H20746D66 ' 'fmt '
const as VCCs _data = &H61746164 ' 'data'
type _PCM_FILE_HDR field = 1
  ChunkRIFF        as VCCs  ' 00-03 'RIFF'
  ChunkRIFFSize    as long  ' 04-07 (maximal: filesize-8)
    ChunkID        as VCCs  ' 08-11 'WAVE'
    ChunkFMT       as VCCs  ' 12-15 'fmt '
    ChunkFMTSize   as long  ' 16-19 (16)
      wFormatTag   as short ' 20-21 (1 (uncompresses) _PCM_FMT_SIZE)
      nChannels    as short ' 22-23 (1|2...)
      nRate        as long  ' 24-27 ( ... 10025,22050,44100 ...)
      nBytesPerSec as long  ' 28-31 (nRate*Framesize)
      Framesize    as short ' 32-33 (nChannels*(nBits\8)
      nBits        as short ' 34-35 (8,16, ...)
    ChunkDATA      as VCCs  ' 36-39 'data'
    ChunkDATASize  as long  ' 40-43 (maximal: filesize-44)
end type

' fill wave header struct 
' return in DataPos the file position of the first sample.
private _
function GetWaveInfo(byval FileName as string , _
                     byref Hdr      as _PCM_FILE_HDR , _
                     byref DataPos  as integer) as boolean

  Dim as integer FileSize, filePos
  var hFile = FreeFile()
  if open(FileName for binary access read As #hFile)=0 then
    FileSize = lof(hFile)
    if FileSize > _PCM_FILE_HDR_SIZE then
      get #hFile,, Hdr.ChunkRIFF
      if Hdr.ChunkRIFF = _RIFF then
        get #hFile,, Hdr.ChunkRIFFSize
        get #hFile,, Hdr.ChunkID
        if Hdr.ChunkID = _WAVE then
          filePos = seek(hFile)
          ' search for "fmt " chunk skip any other chunks
          Hdr.Chunkfmt=0
          while (Hdr.Chunkfmt <> _fmt) and (eof(hFile) = 0)
            get #hFile, filePos, Hdr.Chunkfmt : filePos += 1
          wend
          if Hdr.Chunkfmt = _fmt then
            get #hFile,,Hdr.ChunkfmtSize
            if Hdr.ChunkfmtSize >= _PCM_FMT_SIZE then
              get #hFile,,Hdr.wFormattag
              if Hdr.wFormattag = _WAVE_FORMAT_PCM then
                get #hFile,,Hdr.nChannels
                get #hFile,,Hdr.nRate
                get #hFile,,Hdr.nBytesPerSec
                get #hFile,,Hdr.Framesize
                get #hFile,,Hdr.nBits
                filePos = seek(hFile)
                ' search for "data" chunk skip any other chunks
                Hdr.Chunkdata=0
                while (Hdr.Chunkdata <> _data) and (eof(hFile) = 0)
                  get #hFile, filePos, Hdr.Chunkdata : filePos += 1
                wend
                if Hdr.Chunkdata = _data Then
                  get #hFile,,Hdr.ChunkdataSize
                  if Hdr.ChunkdataSize > 0 and eof(hFile) = 0 Then
                    filePos = seek(hFile)
                    close #hFile
                    DataPos = filePos
                    return true
                  end if ' Chunkdatasize>0
                end if ' Chunkdata=_data
              end if ' wFormattag = WAVE_FORMAT_PCM
            end if ' ChunkfmtSize >= PCM_FMT_SIZE
          end if ' Chunkfmt = _fmt
        end if ' ChunkID = _WAVE
      end if ' ChunkRIFF = _RIFF
    end if ' FileSize > PCM_FILE_HDR_SIZE
    close #hFile
  end if ' open=0
  
  return false
end function

' load samples from *.wav file
' convert from stereo<->mono or wise versa 
' convert from 8->16 bits (if needed)
' return in nBytesLoaded loaded/converted bytes
private _
function Load16BitWave(byval Filename        as string, _
                       byval nRateTarget     as integer, _
                       byval nChannelsTarget as integer, _
                       byref nBytesLoaded    as integer) as any ptr
  const as integer nBitsTarget=16
  dim as _PCM_FILE_HDR hdr
  dim as integer   SeekPos,nBytesTarget,nSamples,nSamplesTarget,i,oPos,cPos
  dim as single    l,r
  dim as double    Scale,nPos
  dim as ubyte     v8
  dim as short     v16
  dim as short ptr p16

  if nChannelsTarget<1 then
    nChannelsTarget=1
  elseif nChannelsTarget>1 then
    nChannelsTarget=2
  endif
  
  oPos=-1
  if GetWaveInfo(Filename,hdr,SeekPos)=true then
    
    nSamples = hdr.ChunkDataSize \ hdr.FrameSize
    
    Scale = hdr.nRate/nRateTarget
    
    nSamplesTarget = nSamples*(1.0/Scale)
    
    nBytesTarget = nSamplesTarget*(nBitsTarget\8)*nChannelsTarget
    
    var hFile = Freefile()
    if open(FileName for binary access read as #hFile)=0 then
      seek #hFile,SeekPos
      
      p16 = callocate(nBytesTarget)
      if (p16 = NULL) then
        print "error: _LoadWave() out of memeory !"        
        close #hFile : return NULL 
      end if
      
      if nSamples<=nSamplesTarget then

        for i=0 to nSamplesTarget-1
          ' jump over in source
          if oPos<>cPos then
            ' read samples l,r -0.5 - 0.5
            if hdr.nBits=8 then
              'read ubyte 0<->255
              get #hFile,,v8
              ' convert to -128.0 <-> +127.0
              l=csng(v8):l-=128
              ' convert to -0.5 <-> +0.5
              l*=(0.5f/128.0f)
              if hdr.nChannels=2 then 
                get #hFile,,v8
                r=csng(v8):r-=128
                ' convert to -0.5 <-> +0.5
                r*=(0.5f/128.0f)  
              else
                r = l ' mono left channel = right channel
              end if
            else ' 16 bits
              get #hFile,,v16 : l=(0.5f/32767.0f)*v16
              if hdr.nChannels=2 then 
                get #hFile,,v16 : r=(0.5f/32767.0f)*v16
              else 
                r = l ' mono left channel = right channel
              end if
            end if
            oPos=cPos
          end if
          ' write every in target
          if nChannelsTarget=1 then
            p16[i    ]=cshort(l*16383f + r*16383f)
          else
            p16[i*2  ]=cshort(l*32767.0f)
            p16[i*2+1]=cshort(r*32767.0f)              
          end if
          nPos+=scale : cPos=int(nPos)
          ' don't read more than len(source)
          if cPos>=nSamples then exit for
          
        next
        
      else ' read every source Sample
      
        scale=(1.0/scale)

        for i=0 to nSamples-1
          
          ' read samples l,r -0.5 - +0.5
          if hdr.nBits=8 then
            'read ubyte 0<->255
            get #hFile,,v8
            ' convert to -128.0 <-> +127.0
            l=csng(v8):l-=128
            ' convert to -0.5 <-> +0.5
            l*=(0.5f/128.0f)
            if hdr.nChannels=2 then 
              get #hFile,,v8
              r=csng(v8):r-=128
              ' convert to -0.5 <-> +0.5
              r*=(0.5f/128.0f)  
            else
              r=l ' mono left channel = right channel
            end if
            
          else
          
            get #hFile,,v16:l=(0.5f/32767.0f)*v16
            if hdr.nChannels=2 then
              get #hFile,,v16:r=(0.5f/32767.0f)*v16
            else 
              r=l ' mono left channel = right channel
            end if
          
          end if
          
          ' jump over in destination
          if oPos<>cPos then 
            if nChannelsTarget=1 then
              p16[cPos    ]=cshort(l*16383.5f + r*16383.5f)
            else
              p16[cPos*2  ]=cshort(l*32767.0f)
              p16[cPos*2+1]=cshort(r*32767.0f)
            end if
            oPos=cPos
          end if
          nPos+=scale:cPos=int(nPos)

          ' don't write more than len(target)
          if cPos >= (nSamplesTarget-1) then exit for
          
        next
        
      end if
      close #hFile
      nBytesLoaded = nBytesTarget
      return p16
  
    end if ' open()=0
  
  end if ' GetWaveInfo()=true
  
  return NULL
end function


type ZOOM_SAMPLE_HEADER ' 48 bytes
  declare constructor
  as zstring * 44 ID  ' 43 chars + 1 NULL = 44
  as ulong        u32 ' &HF62E1D = 16133661      
  as ubyte empty(463) ' 464 bytes + 48 bytes = !!! 512 !!!
end type
constructor ZOOM_SAMPLE_HEADER
  ID = "ZOOM 707-2 SAMPLE DATA VER0001             "
  u32 = &HF62E1D
end constructor

' get *.wav file from command line
var wavFile = command(1)
chdir exepath()
if open(wavFile,for binary,access read, as 1) then
  print "can't read '" & wavFile & "' !"
  beep : sleep : end 1
endif  
close 1
                  
' load and convert wav file to 16bit mono raw data
dim as integer nBytes
dim as ubyte ptr pBytes = Load16BitWave(wavFile,31250,1,nBytes)
if pBytes=NULL then
  print "can't convert '" & wavFile & "' !"
  beep : sleep : end 1
end if  
' convert LE 16bit to BE 16bit mono channel
for i as integer = 0 to nBytes-1 step 2
  swap pBytes[i],pBytes[i+1]
next  
' write ZOOM 707II sample file
dim as ZOOM_SAMPLE_HEADER smpHeader
var smpFile = left(wavFile,len(wavFile)-4) & ".BIN"
if open(smpFile,for binary,access write, as 1) then
  print "can't write '" & smpFile & "' !"
  beep : sleep : end 0
endif
' write ZOOM 707II header (512 bytes)
put #1,,smpHeader
' write ZOOM 707II 16bit mono samples with 31.25KHz (big endians)
put #1,,*pBytes,nBytes
close 1
print "wrote " & nBytes & " in '" & smpFile & "'"
deallocate pBytes
print "ok"
Last edited by D.J.Peters on Oct 12, 2022 18:49, edited 2 times in total.
D.J.Peters
Posts: 8575
Joined: May 28, 2005 3:28
Contact:

Re: WAV to Zoom 707II guitar effect sample converter.

Post by D.J.Peters »

Source of info (and more info) about the Zoom 707II can be found here: An overview of the Zoom 707II

Zoom 707 II is nothing less than an effects rack in a box.
Image
The Analogue (and first) section includes your basic Compression, Limiting, Noise Gate, Gain, Distortion, Sustain, Fuzz and EQ functions.
The optional Cabinet Simulation (which affects all patches and is really just more EQ'ing) is also analogue.

These analogue elements allow you to create your basic guitar sound or 'flavour' for a patch.
The diversity of possible sounds is impressive.
One can recreate most popular guitarists' sounds and/or amazing and totally original sounds in minutes.
Importantly, the analogue section has been completely redesigned.

The Digital section features the full range of DSP (Digital Signal Processing) functions including:
Chorus, Flange, Phase, Tremolo, Wah, Pitch Shift, Ring Modulation, several Delay / Echo options,
various Reverb settings and more.
The Pitch Shift option includes a range of steps from -2 to +2 octaves,
making for some great harmony effects. The tracking is flawless.

For control over sound ambience, the Reverb options include a simple Tone control
to increase/reduce the brightness of reflected sounds,
while offering a useful array of (now standard) reverb environments (Room, Hall, Plate, etc.).

All DSP options can be set up individually and may be used in combination (e.g. Chorus + Delay / Reverb).

The pedal can be assigned to perform various effect parameter control functions
(e.g. modulation depth, delay length, pitch frequency, etc.),
as well as the expected standard Volume and Wah.
The Volume Pedal function can also be assigned as Pre or Post delay effects.

The Zoom 707 II also has a built-in Rhythm function (a rather simple drum machine)
that provides a selection of useful beats and patterns in various styles for practice or jamming.
While these are factory presets with only Tempo and Volume controls,
the quality is actually quite respectable and adequate for jamming.
Last edited by D.J.Peters on Oct 12, 2022 18:50, edited 1 time in total.
Dr_D
Posts: 2439
Joined: May 27, 2005 4:59
Contact:

Re: WAV to Zoom 707II guitar effect sample converter.

Post by Dr_D »

Cool stuff man! :D
Post Reply