1

i would appreciate if some windows batch guru may be willing to help me clean my code. Ok the .bat is working, but it's messy implementation, and i'd like to make it simpler and cleaner on 2 things :

1-i've put a "sleep 1 s" to let the "copy" on the line above complete, else it seems the "for ()" is executed multitask-ingly with the rest of the program, is that right ??

2-i'd be willing to use arrays to store filenames instead of re-listing them every time!

[if you wonder : what's the code is doing ? it is concatenating MP3 files : silences.mp3 + inductions.mp3 to create a long track with the inductions with a bit of randomness]

thanks to anyone helping!


@ECHO OFF
CLS

SETLOCAL EnableExtensions EnableDelayedExpansion

REM -----------   SET VALUES   -----------
REM   RECOMMENDED FORMAT : MP3 CBR 16kHz --> 8kbps silence  & 16kbps voice
SET Folder=.\inductions\
SET SilenceMP3=1s-blank.mp3
SET OutputMP3=output.mp3

REM -----------   GET USER INPUTS   -----------
SET /p MAX_TIME=Maximum time seconds  : 
SET /p MIN_TIME=Minimum time seconds  : 
SET /p     LOOP=Nombre de repetitions : 

SET /a MAX_TIME-=MIN_TIME


REM -----------   COUNTING NB OF INDUCTION AVAIL   -----------
SET Nb_induction=0
for /r "%folder%" %%a in (*.*) do ( SET /a Nb_induction+=1 )

REM -----------   INIT THE OUTPUT WITH 1s SILENCE   -----------
copy /Y %SilenceMP3% %OutputMP3%  1> nul

for /L %%i IN (0,1,%LOOP%) do (
    REM -----------   GET A RANDOM TIME SILENCE   -----------
    SET /A REP=!RANDOM! %% !MAX_TIME! + !MIN_TIME!

    REM -----------   ADD !REP! seconds of silence   -----------
    for /L %%j IN (0,1,!REP!) do (      
        copy /B %OutputMP3% + /B %SilenceMP3% /B %OutputMP3%  1> nul
        )
sleep 1

    REM -----------   ADD RANDOM INDUCTION   -----------
    SET /a x=!RANDOM! %% %Nb_induction%

    for /r "%folder%" %%a in (*.*) do (
        IF !x!==0 ( SET InductionMP3=%%a )
        SET /a x-=1
        )

    copy /B %OutputMP3% + /B !InductionMP3! /B %OutputMP3%   1> nul
echo %%i
    )

Antonio (1st thanks), your code outputs:

Maximum time seconds  : 20
Minimum time seconds  : 10
Nombre de repetitions : 2
AVAILABLE INDUCTION FILES:
InductionMP3[1]=D:\auto-induction\inductions\je_sors_de_mon_corps1.mp3
InductionMP3[2]=D:\auto-induction\inductions\je_sors_de_mon_corps2.mp3
InductionMP3[3]=D:\auto-induction\inductions\je_sors_de_mon_corps3.mp3
RANDOM INDUCTION # 1: D:\auto-induction\inductions\je_sors_de_mon_corps1.mp3
copy /B output.mp3 + /B D:\auto-induction\inductions\je_sors_de_mon_corps1.mp3 /
B output.mp3
0
RANDOM INDUCTION # 1: D:\auto-induction\inductions\je_sors_de_mon_corps1.mp3
copy /B output.mp3 + /B D:\auto-induction\inductions\je_sors_de_mon_corps1.mp3 /
B output.mp3
1
RANDOM INDUCTION # 2: D:\auto-induction\inductions\je_sors_de_mon_corps2.mp3
copy /B output.mp3 + /B D:\auto-induction\inductions\je_sors_de_mon_corps2.mp3 /
B output.mp3
2

cmd issue: (don't understand this mysterious one? so i kept modulo op for now)

SET /a x=(!RANDOM! * Nb_induction) / 32768 + 1

yield error:

/ was unexpected at this time.

i tried () more : SET /a x=((!RANDOM! * Nb_induction) / 32768 ) + 1 no more success!


1- %% modulo operator is the remainder of an integer division: set /A mod=13 %% 5 gives 3; see en.wikipedia.org/wiki/Random_number_generation.

Agree, your solution is the proper math/stat implementation (if win can handle multiply/divide correctly ;-) )

2- I show the !InductionMP3[!x!]! example just for educative purposes, but it can NOT be used (as I said in my answer).

Right, i tried to twist it around !InductionMP3[!x!]!, !InductionMP3[%x%]! etc... still don't get it with the EnableDelayedExpansion stuff %a% %%a !a! etc...

3- I added some ECHO commands in my code that aids in finding problems. Please, copy the program above again, run it and post the output in code format as an edit in your question (NOT in a comment).

Sorry for the messy reply

4- Did you read the post about array management? I think it is not so difficult, but feel free to ask any question about it

I did, arrays are quite ok/easy, it's just the %variable% thing still out of my control...

alex
  • 35
  • 1
  • 6
  • copy is an internal command for CMD and the CMD should wait until copy command return a result.Why do you need a SLEEP?Arrays are not so easy for emulation - you can check this script : http://jakash3.wordpress.com/2009/12/18/arrays-in-batch/ – npocmaka Jan 09 '13 at 18:38
  • I know i should not have any parallel execution in this code. Still without the SLEEP, i get "The process cannot access the file because it is being used by another process." in the cmd window. And in the output file, i obviously have some 2nd COPY missed! So my guess is that somehow some command are overlapping, don't know how !! :-( – alex Jan 10 '13 at 10:54

1 Answers1

2

Some comments about your code:

  • FOR command is not executed in paralell, so SLEEP command is not required.

  • Variables in SET /A command does not require to be expanded; the SET command correctly takes its value by itself.

  • It is not a good idea to divide !RANDOM! by the max. limit and get the remainder because the resulting number have not the same distribution of the original !RANDOM!, so you may get multiple repetitions of the same result. The right way to use !RANDOM! is shown below.

  • Array management in Batch is pretty simple, as described in this post.

This is my version of your code:

@ECHO OFF
CLS

SETLOCAL EnableExtensions EnableDelayedExpansion

REM -----------   SET VALUES   -----------
REM   RECOMMENDED FORMAT : MP3 CBR 16kHz --> 8kbps silence  & 16kbps voice
SET Folder=.\inductions\
SET SilenceMP3=1s-blank.mp3
SET OutputMP3=output.mp3

REM -----------   GET USER INPUTS   -----------
SET /p MAX_TIME=Maximum time seconds  : 
SET /p MIN_TIME=Minimum time seconds  : 
SET /p     LOOP=Nombre de repetitions : 

SET /a MAX_TIME-=MIN_TIME


REM -----------   COUNTING NB OF INDUCTION AVAIL   -----------
REM -- AND CREATE THE INDUCTION ARRAY AT THE SAME TIME --
ECHO AVAILABLE INDUCTION FILES:
SET Nb_induction=0
for /r "%folder%" %%a in (*.*) do (
    SET /a Nb_induction+=1
    SET InductionMP3[!Nb_induction!]=%%a
    ECHO InductionMP3[!Nb_induction!]=%%a
)


REM -----------   INIT THE OUTPUT WITH 1s SILENCE   -----------
copy /Y %SilenceMP3% %OutputMP3%  1> nul

for /L %%i IN (0,1,%LOOP%) do (
    REM -----------   GET A RANDOM TIME SILENCE   -----------
    SET /A "REP=(!RANDOM! * MAX_TIME) / 32768 + MIN_TIME"

    REM -----------   ADD !REP! seconds of silence   -----------
    for /L %%j IN (0,1,!REP!) do (      
        copy /B %OutputMP3% + /B %SilenceMP3% /B %OutputMP3%  1> nul
    )
    REM sleep 1  NOT REQUIRED

    REM -----------   ADD RANDOM INDUCTION   -----------
    SET /a "x=(!RANDOM! * Nb_induction) / 32768 + 1"

    for %%x in (!x!) do (
        ECHO RANDOM INDUCTION # %%x: !InductionMP3[%%x]!
        ECHO copy /B %OutputMP3% + /B !InductionMP3[%%x]! /B %OutputMP3%
        copy /B %OutputMP3% + /B !InductionMP3[%%x]! /B %OutputMP3%   1> nul
    )

    echo %%i
)

Note that in the last COPY command, the name of the random induction file would be something like this:

    copy /B %OutputMP3% + /B !InductionMP3[!x!]! /B %OutputMP3%   1> nul

However, it is no possible to nest a delayed expansion inside another one, so a FOR command is used to achieve the first expansion and use its replaceable value in the second one. See the previous link for further details.

Antonio

Community
  • 1
  • 1
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Antonio! thanks a lot for your prompt answer! (SET /A REP=!RANDOM! %% !MAX_TIME! + !MIN_TIME! is ok as %% is a modulo op not a divide op) the array[] populate is OK but the retrieving is NOT!! THE CODE : echo "DEBUG: copy /B %OutputMP3% + /B !InductionMP3[%%x]! /B %OutputMP3% 1> nul" echo "DEBUG: copy /B %OutputMP3% + /B !InductionMP3[!x!]! /B %OutputMP3% 1> nul" RESULT AS : "DEBUG: copy /B output.mp3 + /B /B output.mp3 1> nul" "DEBUG: copy /B output.mp3 + /B x /B output.mp3 1> nul" So i cannot get the !InductionMP3[!x!]! properly... hardcoded !Induction[0]! is Ok – alex Jan 10 '13 at 10:51
  • I must confess, i'm still confused about %var%, %%var, !var! etc... I seldom write code, and most of the time make copy/paste from other code found on the net. – alex Jan 10 '13 at 10:59
  • 1- `%%` modulo operator is the remainder of an integer division: `set /A mod=13 %% 5` gives 3; see http://en.wikipedia.org/wiki/Random_number_generation. 2- I show the `!InductionMP3[!x!]!` example just for educative purposes, but it can NOT be used (as I said in my answer). 3- I added some ECHO commands in my code that aids in finding problems. Please, copy the program above again, run it and post the output in code format as an edit in your question (NOT in a comment). 4- Did you read the post about array management? I think it is not so difficult, but feel free to ask any question about it. – Aacini Jan 10 '13 at 17:46
  • Just enclose the variable assignment in quotes; I did it already in the code. If you want to use the modulo method in my code, be sure to add 1 to "x" random induction subscript variable, because modulo generate random numbers between 0 and N-1, and the array have elements from 1 to N. – Aacini Jan 11 '13 at 14:52