Shop OBEX P1 Docs P2 Docs Learn Events
Recursive SPIN routine - USB thumbdrive file find — Parallax Forums

Recursive SPIN routine - USB thumbdrive file find

Ron CzapalaRon Czapala Posts: 2,418
edited 2011-11-15 13:03 in Propeller 1
I wanted to develop a routine for my VMUSIC2 project which would locate a particular MP3 file on a USB thumbdrive inserted into the VMUSIC2.
Of course, there can be many nested folders and it seemed that a recursive routine was the best approach.
Since the Parallax memory stick datalogger module is similar to the VMUSIC2 (both use the Vinculum VNC1L USB host controller), this code should work
with the datalogger.

I have many vbscripts that do this using the FileSystemObject in the Windows scripting runtime DLL but doing this in SPIN for a Propeller
would be a different scenario due to memory constraints, etc.

What I did was define a global byte array in the DAT section which would hold up to 500 thirteen byte top-level directory names i.e. directories immediately under the root.

Then I created recursive method which defines a local variable to store up to 10 sub-folder names. It calls itself to handle nested sub-folders.
It passes an index pointer, directory counter, and subfolder array address to the supporting methods.
As it works it way through the directory structure, it looks at each file name and compares it to the search filename.

I use a variable named dirlvl to keep track of the nesting level. It is also used to build a array of the directory names maintaining a path to the current folder.
Of course, as the routine calls itself, more memory is being allocated and then freed up when a directory has been processed
and processing resumes with the parent directory.

I am trying to figure out the best way to monitor available memory during the recursion.
One way would be to check the dirlvl variable, but there may be a better way.
I also want to see if I can speed it up...

[SIZE=2]CON
  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000[/SIZE]
[SIZE=2]' -------  Pin assigments ------
  vm_rts   = 0             ' Request To Send --> VMusic2 pin 6  (CTS#)  - green 
  vm_rx    = 1             ' Receive Data    <-- VMusic2 pin 5  (TXD)   - yellow
  vm_tx    = 2             ' Transmit Data   --> VMusic2 pin 4  (RXD)   - orange
  vm_cts   = 3             ' Clear To Send   <-- VMusic2 pin 2  (RTS#)  - brown[/SIZE]
[SIZE=2]vm_port       = 0
  BAUD          = 9_600         ' LCD baud rate
  maxdirs       = 500           ' number of directory names to table
  maxpath       = 10            ' max number of folder names in path for recursive routine
  maxsubdirs    = 12            ' number of sub folders allowed under top level folder
  maxbuff       = 60            ' size of buffer for parsing VM2 serial output
  
VAR
  long useser           ' USB serial connection detected T/F
  long debugsw          ' control output to Parallax Terminal
  long diskchk          ' "No Disk" check
  byte fname[13]           ' file name playing
  byte rxbuff[maxbuff]     ' work buffer 
  byte mp3title[maxbuff]   ' hold song title
  byte artist[maxbuff]     ' hold artist
  byte buffptr[/SIZE]
[SIZE=2]word dircntr          'directory counter
  long dirptr           'directory pointer
  byte dirlvl           'directory nesting level
  byte findsw           '1=recursive search for filename
  long pathptr          'path pointer[/SIZE]
[SIZE=2]
OBJ
  uarts         : "pcFullDuplexSerial4FC" '1 COG for 4 serial ports
  Debug         : "FullDuplexSerial"  '"SerialMirror"  '"Extended_FDSerial"
  I2C           : "Basic_I2C_Driver_1"
' strng         : "ASCII0_STREngine_1"   
  
PUB Main | idx     
  dira[vm_rts]~~                 
  outa[vm_rts]~                        ' Take Vinculum Out Of Reset - set low
  
  useser := false
  if ina[31] == 1                      ' RX (pin 31) is high if USB is connected
    Debug.start(31, 30, 0, 57600)      ' ignore tx echo on rx
    useser := true                     ' Debug serial connection is active
    debugsw := true
  else
    outa[30] := 0                      ' Force Propeller Tx line LOW if USB not connected
    
''-----------------------
''override debugsw to disable terminal displays
' debugsw := false     
''-----------------------[/SIZE]
[SIZE=2]if debugsw == true
    Debug.str(string(16,"Please wait",13))  ' CLS, disp msg[/SIZE]
[SIZE=2]I2C.Initialize(I2C#BootPin)               ' initialize I2C object
  
  diskchk := 1[/SIZE]
[SIZE=2]uarts.Init                           'start four port serial cog
'  uarts.AddPort(vm_port,vm_rx,vm_tx,vm_cts,vm_rts,UARTS#DEFAULTTHRESHOLD,UARTS#NOMODE,UARTS#BAUD9600)
  uarts.AddPort(vm_port,vm_rx,vm_tx,vm_cts,vm_rts,UARTS#DEFAULTTHRESHOLD,UARTS#INVERTCTS,UARTS#BAUD9600)
  uarts.Start    
  Read_VMResp[/SIZE]
[SIZE=2]waitcnt(clkfreq * 2 + cnt)
  uarts.str(vm_port, string("IPA",$0D)) 'monitor mode ascii
  Read_VMResp
  waitcnt(clkfreq / 2 + cnt)   [/SIZE]
[SIZE=2]uarts.str(vm_port, string("ECS",$0D)) 'extended command set
  Read_VMResp
  waitcnt(clkfreq / 2 + cnt)   [/SIZE]
[SIZE=2]uarts.str(vm_port, string("CD / "))     'CD root                  
  Read_VMResp[/SIZE]
[SIZE=2]
{  store directory names in dirs table
}[/SIZE]
[SIZE=2]ReadDirectory            'read and store directory names[/SIZE]
[SIZE=2]
  bytemove(@fname, string("STARBU~1.MP3"),13)
  FindFile[/SIZE]
[SIZE=2]
  repeat
    waitcnt(clkfreq * 5 + cnt)   [/SIZE]
[SIZE=2]{  store directory names in dirs table
} 

PUB ReadDirectory | idx
  dircntr := 0
  dirptr := @dirs    
'  debug.dec(@rxbuff)   'address of rxbuff
'  debug.tx(13)
  debug.str(string("dirs addr: "))
  debug.dec(dirptr)     'address of dirs
  debug.tx(13)
  buffptr := 0  
  uarts.str(vm_port, string("DIR",$0D))   'directory list
  Read_Dirs[/SIZE]
[SIZE=2]if debugsw == true
    repeat idx from 0 to dircntr-1
      dirptr := @dirs + (idx * 13)
      debug.dec(dirptr)
      debug.tx(32)
      debug.str(dirptr)
      debug.tx(13)[/SIZE]
[SIZE=2]buffptr := 0  
  waitcnt(clkfreq * 2 + cnt) [/SIZE]
[SIZE=2]{ Read directory names (under root) and store into dirs byte array
  Each directory name takes 13 bytes
}

PUB Read_Dirs| iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
'      debug.tx(iobyte)
      if Process_Directory(iobyte)
        if debugsw == true 
          debug.dec(dircntr)
          debug.str(string(" Directories",13))
      
PUB Process_Directory(datain)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if StoreDir
      return true
    buffptr :=0
'    bytefill(@rxbuff, 0, maxbuff)    'Clear Buff to 0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]
PUB StoreDir | dirlen
  if findString(@rxbuff,string("D:\>")) > 0
    return true
  dirlen := findString(@rxbuff,string(" DIR")) - @rxbuff    'calc length of directory name
  if dirlen > 0              'length of directory name
'    debug.dec(dirlen)
'    debug.tx(13)
    bytemove(dirptr, @rxbuff, dirlen)
    dircntr++
    dirptr := @dirs + (dircntr * 13)    'calc addr to store next dir name  
'    debug.dec(dirptr)
'    debug.tx(13)[/SIZE]
[SIZE=2]
PUB FindFile | idx
  findsw := 1           'enable filename match 
  debug.str(string("Searching for: "))
  debug.str(@fname)
  debug.tx(13)
'loop thru top level directories
  repeat idx from 0 to dircntr-1      
    dirptr := @dirs + (idx * 13)
    dirlvl :=0
'   debug.str(dirptr)
'   debug.tx(13)
    Recurse(dirptr)             'call recursive routine to search for file
  debug.str(string("Done Searching"))
  findsw := 0           'disable filename match 
  
PUB Recurse(parent)| fldrptr, fldrcntr, fldrs[(maxsubdirs * 13) / 4], idx, psize
  dirlvl++
' if dirlvl == 1
'   bytefill(@dirpath,0,maxpath*13)
  pathptr := @dirpath + ((dirlvl-1) * 13)
  psize := strsize(parent)
  bytemove(pathptr, parent, psize)
  debug.str(string(13,"Path: "))
   repeat idx from 0 to dirlvl-1
     debug.tx("\")
     debug.str(@dirpath + (idx * 13))
  debug.tx(13)
{
  debug.tx(13)
  debug.str(string("- - - - - - - - - - - "))
  debug.str(string("dir level: "))
  debug.dec(dirlvl)
  debug.tx(13)
}
  fldrptr := @fldrs
  fldrcntr := 0
  longfill(@fldrs, 0, 39)
  
{
  debug.str(string("fldrs addr: "))
  debug.dec(fldrptr)
  debug.tx(13)
}
  if findString(parent,string("/")) <> @parent
{
    debug.str(string("CD "))
    debug.str(fldr)
    debug.tx(13)
}
    uarts.str(vm_port, string("CD "))
    uarts.str(vm_port, parent)           'change directory
    uarts.tx(vm_port, $0D)               'carriage return
    Read_VMResp[/SIZE]
[SIZE=2]{
  buffptr := 0
  if findsw == 1
    uarts.str(vm_port, string("DIR "))
    uarts.str(vm_port, @fname)            'dir 'filename'
    uarts.tx(vm_port,$0D)  
    Read_VMResp
}
  
  uarts.str(vm_port, string("DIR",$0D))   'directory list
  Read_SubDirs(@fldrptr, @fldrcntr, @fldrs)[/SIZE]
[SIZE=2]'for each sub folder
  if fldrcntr > 0
    repeat idx from 0 to fldrcntr-1
      fldrptr := @fldrs + (idx * 13)
      Recurse(fldrptr)[/SIZE]
[SIZE=2]uarts.str(vm_port, string("CD ..",$0D))       'change to parent directory
  buffptr := 0
  pathptr := @dirpath + ((dirlvl-1) * 13)
  bytefill(pathptr,0,13)
  dirlvl--[/SIZE]
[SIZE=2]
PUB Read_SubDirs(fldrptr,fldrcntr,fldrs) | iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
'      debug.tx(iobyte)
      if Process_SubDirectory(iobyte, fldrptr,fldrcntr,fldrs)
'        if debugsw == true 
'          debug.dec(fldrcntr)
'          debug.str(string(" Directories",13))
      
PUB Process_SubDirectory(datain,fldrptr,fldrcntr,fldrs)
'  debug.str(string("proc dir: "))
'  debug.dec(long[fldrptr])
'  debug.tx(32)
'  debug.dec(long[fldrcntr])
'  debug.tx(13)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if StoreSubDir(fldrptr,fldrcntr,fldrs)
      return true
    buffptr :=0
'    bytefill(@rxbuff, 0, maxbuff)    'Clear Buff to 0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]PUB StoreSubDir(fldrptr,fldrcntr,fldrs) | dirlen
  if findString(@rxbuff,string("D:\>")) > 0
    return true
  if findString(@rxbuff, string(". DIR")) == @rxbuff 
    return
  if findString(@rxbuff, string(".. DIR")) == @rxbuff
    return
  dirlen := findString(@rxbuff,string(" DIR")) - @rxbuff    'calc length of directory name
  if long[fldrcntr] > (maxsubdirs - 1)                      'fldrs array is full
    debug.str(string("Too many sub folders"))
    debug.tx(13)
    return
  if dirlen > 0              'length of directory name
'    debug.str(string("store dir: "))
'    debug.dec(long[fldrptr])
'    debug.tx(32)
'    debug.dec(long[fldrcntr])
'    debug.tx(32)
'    debug.dec(dirlen)
'    debug.tx(13)
    bytemove(long[fldrptr], @rxbuff, dirlen)
    long[fldrcntr]++
    long[fldrptr] := fldrs + (long[fldrcntr] * 13)    'calc addr to store next dir name
  else
    if byte[@rxbuff][0] <> 0       ' ignore blank line at top of dir listing
      debug.str(@rxbuff)           ' file, not directory
      debug.tx(13)
      if findsw == 1
        if findString(@rxbuff, @fname) == @rxbuff
          debug.str(string("------> Found it!"))
          debug.tx(13)[/SIZE]
[SIZE=2]PUB Read_VMResp | iobyte
  iobyte:=0
  repeat
    iobyte:=uarts.rxtime(vm_port,500)
    if iobyte < 0 
      quit
    else
       Buffer_datain(iobyte)
'     if debugsw == true   
'       debug.tx(iobyte)[/SIZE]
[SIZE=2]PUB Buffer_datain(datain)
  if datain == 13                     'carriage return?
    rxbuff[buffptr++] := 0
    if debugsw == true 
      DisplayBuff
    buffptr :=0
    return
  else  
    if buffptr < maxbuff - 1 
      rxbuff[buffptr++] := datain     'add byte to buffer[/SIZE]
[SIZE=2]PUB DisplayBuff | idx
  if strsize(@rxbuff) < 1                         'suppress blank line after any dir command
    return true
  if findString(@rxbuff,string("D:\>")) > 0       'suppress standard response
'    debug.tx(".")   
    return true
  if findString(@rxbuff,string("Command Failed")) > 0 
    return true[/SIZE]
[SIZE=2]if findsw == 1
    if findString(@rxbuff, @fname) == @rxbuff
      debug.str(string("------> Found it!"))
      debug.tx(13)   [/SIZE]
[SIZE=2]debug.str(@rxbuff)
  debug.tx(13)[/SIZE]
[SIZE=2]PUB findString(stringToSearch, stringToFind) | index, size ' 7 Stack Longs
'// Author: Kwabena W. Agyeman  
' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
' // Searches a string of characters for the first occurence of the specified string of characters.
' //
' // Returns the address of that string of characters if found and zero if not found.
' //
' // StringToSearch - A pointer to the string of characters to search.
' // StringToFind - A pointer to the string of characters to find in the string of characters to search.
' ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////[/SIZE]
[SIZE=2]size := strsize(stringToFind)
  if(size--)[/SIZE]
[SIZE=2]repeat strsize(stringToSearch--)
      if(byte[++stringToSearch] == byte[stringToFind])[/SIZE]
[SIZE=2]repeat index from 0 to size
          if(byte[stringToSearch][index] <> byte[stringToFind][index])
            result := true
            quit[/SIZE]
[SIZE=2]ifnot(result~)
          return stringToSearch
  
DAT
  nodisk  byte "No Disk",0
  dirs    byte $00[maxdirs*13]         'array of directory names under root
  dirpath byte $00[maxpath*13]              'allow ten deep directory path [/SIZE]

Here is the terminal output using a some small folders - you can see the line "
> Found it!" when the file has been located.
[SIZE=2]Please wait
Ver 03.68VMSC1F On-Line:
Device Detected P2
No Upgrade
dirs addr: 96
3 Directories
96 JAZZ
109 VARIOU~1
122 PORTER
Searching for: STARBU~1.MP3[/SIZE]
[SIZE=2]Path: \JAZZ[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ1
BLOWIN~1.MP3
BLUEDA~1.MP3
BODYHE~1.MP3
HEARTS~1.MP3
HEAVEN.MP3
LOSTSU~1.MP3
NORTHE~1.MP3
REALLY~1.MP3
SEEYOU~1.MP3
SOUNDO~1.MP3
STROLL~1.MP3
WITHOU~1.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ2
CANYOU~1.MP3
DOYOUR~1.MP3
GOODLO~1.MP3
INNERC~1.MP3
JUSTCA~1.MP3
SLOMOT~1.MP3
SMOOTH~1.MP3
SOMUCH~1.MP3
SUMMER~1.MP3
TIMETO~1.MP3
WALKIN~1.MP3
WONDER~1.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ3
DON'TL~1.MP3
DOWNSO~1.MP3
DREAMS.MP3
LONDON~1.MP3
LONDON~2.MP3
LOSTIN~1.MP3
NEWDAW~1.MP3
NIGHTC~1.MP3
REDZON~1.MP3
STARCH~1.MP3
STILLT~1.MP3
TRIPPI~1.MP3
VENTUR~1.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ4
KEYS_4.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ5
KEYS_5.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ6
KEYS_6.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ7
KEYS_7.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ8
KEYS_8.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ9
KEYS_9.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ10
KEYS_10.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ11
KEYS_11.MP3[/SIZE]
[SIZE=2]Path: \JAZZ\JAZZ12
KEYS_12.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1[/SIZE]
[SIZE=2]Path: \VARIOU~1\THEBIG~1
AWHITE~1.MP3
DANCIN~1.MP3
GOODLO~1.MP3
ISECON~1.MP3
ITSTHE~1.MP3
NATURA~1.MP3
TELLHI~1.MP3
TOOMAN~1.MP3
TRACKS~1.MP3
WHAT'S~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\TEENAG~1
BOBBYS~1.MP3
BORNTO~1.MP3
CHANCE~1.MP3
CRYMEA~1.MP3
DEVILO~1.MP3
HOLDME~1.MP3
IT'SAL~1.MP3
IT'SON~1.MP3
MYHEAR~1.MP3
MYSPEC~1.MP3
PRETTY~1.MP3
SEAOFL~1.MP3
SEALED~1.MP3
TEENAN~1.MP3
TELLLA~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\ONEHIT~1
986~1.MP3
COMEON~1.MP3
DOMINI~1.MP3
JUNGLE~1.MP3
MONTEG~1.MP3
ONETIN~1.MP3
REFLEC~1.MP3
YOUDON~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\MOREPU~1
DOYOUR~1.MP3
HANDST~1.MP3
IKNOWT~1.MP3
I'VEDO~1.MP3
JEOPARDY.MP3
LOVEIS~1.MP3
RIO.MP3
ROCKME~1.MP3
SHOUT.MP3
THELOO~1.MP3
THEPOW~1.MP3
THESAF~1.MP3
WALKIN~1.MP3
WOULDI~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\HARDTO~1.6MO
(DOWNA~1.MP3
(JUSTL~1.MP3
AKOOKI~1.MP3
BLACKI~1.MP3
EVERYD~1.MP3
EVERYB~1.MP3
GUANTA~1.MP3
HOLDME~1.MP3
I'MLEA~1.MP3
LAURIE~1.MP3
LIGHTN~1.MP3
MASTER~1.MP3
MYBOYL~1.MP3
NOTHIN~1.MP3
PATAPA~1.MP3
RUMORS.MP3
SAILOR~1.MP3
THEMOR~1.MP3
TOBACC~1.MP3
WALKAW~1.MP3
WITCHI~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\HARDTO~1.560
ANGELO~1.MP3
B-A-B-Y.MP3
DEEPPU~1.MP3
DON'TS~1.MP3
JOHNNY~1.MP3
LET'ST~1.MP3
NEXTPL~1.MP3
ONEBOY~1.MP3
SIXTEE~1.MP3
TAKEAL~1.MP3
TURNAR~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\HARDTO~1.219
BOBBY'~1.MP3
DIANE.MP3
DOMINI~1.MP3
ISAWLI~1.MP3
LITTLE~1.MP3
LITTLE~2.MP3
LOVERP~1.MP3
NAVYBL~1.MP3
PATCHES.MP3
POPSIC~1.MP3
SUGARS~1.MP3
WOODEN~1.MP3
YOUDON~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\DICKCL~1.2
CHAPEL~1.MP3
DUKEOF~1.MP3
EVERYB~1.MP3
HARLEM~1.MP3
LEADER~1.MP3
LETTHE~1.MP3
POETRY~1.MP3
THENYO~1.MP3
THOSEO~1.MP3
TILLIK~1.MP3
TOSSSI~1.MP3
VENUSI~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\DICKBA~1.2
ANGELO~1.MP3
CINNAMON.MP3
EVERLA~1.MP3
EXPRES~1.MP3
GIMMEG~1.MP3
LETITO~1.MP3
MORNIN~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\BILLBO~1
EASIER~1.MP3
FINGER~1.MP3
HE'SSO~1.MP3
LOUIE_~1.MP3
MYBOYF~1.MP3
SUGARS~1.MP3
SURFCI~1.MP3
SURFIN~1.MP3
WALKLI~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\BILLBO~2
ALLEY-~1.MP3
CATHY'~1.MP3
HANDYM~1.MP3
RUNNIN~1.MP3
SAVETH~1.MP3
WALK_D~1.MP3[/SIZE]
[SIZE=2]Path: \VARIOU~1\AFTERN~1
CAMPBE~1.MP3
DAWN-K~1.MP3
GLADYS~1.MP3
HARRYN~1.MP3
JIMCRO~1.MP3
JOSEFE~1.MP3
STARBU~1.MP3
------> Found it!
STARLA~1.MP3
STEVEF~1.MP3
THEHOL~1.MP3
THELEM~1.MP3
THERAS~1.MP3[/SIZE]
[SIZE=2]Path: \PORTER[/SIZE]
[SIZE=2]Path: \PORTER\PORTONE
CANDLE~1.MP3
DBBLUE~1.MP3
FLIGHT~1.MP3
FOREVE~1.MP3
JUSTWA~1.MP3
LAKESH~1.MP3
LAYYOU~1.MP3
ONEMOR~1.MP3
WEAREO~1.MP3
WISHFU~1.MP3
Done Searching[/SIZE]

 

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2011-11-15 08:09
    Checking the directory level is a good proxy for the memory usage of the recursive routine since you know how much memory each recursion takes.

    If you're going to be looking up file names often, but changing the contents of the memory stick infrequently, you should consider having a separate program that recursively goes through the directory structure and builds a database that can be easily searched. This database could be stored on a root-level file. If you want to get fancy, you could use a Winbond SPI flash memory to hold the database. These come in sizes up to several megabytes and there's a driver in the ObEx that provides for named files and includes a program loader.
  • Ron CzapalaRon Czapala Posts: 2,418
    edited 2011-11-15 08:20
    Mike Green wrote: »
    Checking the directory level is a good proxy for the memory usage of the recursive routine since you know how much memory each recursion takes.

    If you're going to be looking up file names often, but changing the contents of the memory stick infrequently, you should consider having a separate program that recursively goes through the directory structure and builds a database that can be easily searched. This database could be stored on a root-level file. If you want to get fancy, you could use a Winbond SPI flash memory to hold the database. These come in sizes up to several megabytes and there's a driver in the ObEx that provides for named files and includes a program loader.

    Thanks for the suggestions Mike. I thought about using a vbscript to create a text file with the filenames and paths to load onto the drive beforehand.

    The reason behind this effort was that when playing songs randomly on the VMUSIC2, it informs you of the filename playing, but not the path. I wanted to be able to delete the MP3 currently playing but you have to stop playing it first. When you do that, the VMUSIC returns to the root directory so you don't know what folder the file is in.

    EDIT: Of course, with the limiting DOS 8.3 filenames, you could end up with two different MP3s with the same name in different folders.

    The Winbond flash memory sounds interesting too!
  • Mike GreenMike Green Posts: 23,101
    edited 2011-11-15 09:10
    You could also scan the MP3 files for their metadata (see here) and save the metadata in the database file along with the full path to the file. You could certainly have a script program on your PC to create the database, but you could also have a Spin program that would do it.

    The Winbond flash memories come in sizes up to 8MB in PDIP and the ObEx driver handles up to that size.
  • Ron CzapalaRon Czapala Posts: 2,418
    edited 2011-11-15 09:30
    Mike Green wrote: »
    You could also scan the MP3 files for their metadata (see here) and save the metadata in the database file along with the full path to the file. You could certainly have a script program on your PC to create the database, but you could also have a Spin program that would do it.

    The Winbond flash memories come in sizes up to 8MB in PDIP and the ObEx driver handles up to that size.

    I am very familiar with ID3Tag information and have written DLLs, code to modify tag information, and my own MP3 player in VB6 (using the Windows media player API).
    I also wrote a vb program to delete unneccesay tag items (like the embedded album art,etc) and convert unicode tags to ascii (the VMUSIC2 won't handle unicode). Zip file (here)

    Digikey has the 8Mb PDIP chips for $1.39 - very reasonable!
  • Ron CzapalaRon Czapala Posts: 2,418
    edited 2011-11-15 13:03
    Well, I created a vbscript to create a directory list file on the thumbdrive.
    I attached a ZIP file with the vbscript and this readme.txt file:
    Place the MakeDirList.vbs script on a thumbdrive and double click it in Windows explorer to run it.
    It creates a tab-delimited file called directory.txt listing on the drive by recursively processing each folder and subfolder.
    For each MP3 or WMA file, it creates a line with the 8.3 DOS format filename (shortname), the path (using folder shortnames), and the long filename.
    It sorts the file back to itself and opens it notepad.

    I have over 1010 MP3s on my thumbdrive and the sorted list shows many files with the same shortname in different directories.

    For example, the are eight different songs named "YOU'RE~1.MP3" - songs that begin with "You're".

    It could be a little tricky for the VMUSIC2 to find the right song to delete...
    YOU'RE~1.MP3 \@MISC You're Sixteen.mp3
    YOU'RE~1.MP3 \BARRYW~1\ALLTIM~1 You're the First, the Last, My Everything.mp3
    YOU'RE~1.MP3 \CARLYS~1 You're So Vain.mp3
    YOU'RE~1.MP3 \PATSYC~1\THEPAT~1 You're Stronger Than Me.mp3
    YOU'RE~1.MP3 \SHANIA~1 You're Still The One.mp3
    YOU'RE~1.MP3 \THEBES~3 You're a Big Girl Now.mp3
    YOU'RE~1.MP3 \THESTY~1\THEBES~1 You're a Big Girl Now.mp3
    YOU'RE~1.MP3 \THEVOG~1 You're The One.mp3
Sign In or Register to comment.