Hi ,
I have always enjoyed that sound :biggrin:
How is that sound accessed on a PC?
Is there a was to do that with masm?
Or is it a source with beeps?
if you are talking about the "whish" sound like the one Kristanna Loken makes in Terminator 3,
it comes from the modem speaker - it is the actual audio that goes back and forth over the phone
you might be able to google around and get a WAV file of it
http://www.soundjay.com/dial-up-modem-sound-effect.html (http://www.soundjay.com/dial-up-modem-sound-effect.html)
WAV files are easy to play and you can add them to your exe as a resource
as far as "enjoying" that sound - lol - i can find you many better things to listen to :lol:
You can do it with Masm, but you'll have to do a lot of experimenting to get the right tones and delays.
Andy
;Telephone.asm
; Simulate telephone ringing
; Help from SuperDave -- a.k.a. DednDave,
; PRODUCE 1 KHz TONE FOR 54.9 mS
; PRODUCE 800 Hz TONE FOR 54.9 mS
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\shell32.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\shell32.lib
include \masm32\macros\macros.asm
.data
.code
start:
mov ecx, 20
@@:
push ecx
invoke Beep, 1000, 55 ; Frequency in hertz and sound duration
invoke Beep, 800, 55
pop ecx
dec ecx
jnz @B
invoke Sleep, 1500
mov ecx, 20
@@:
push ecx
invoke Beep, 1000, 55 ; Frequency in hertz and sound duration
invoke Beep, 800, 55
pop ecx
dec ecx
jnz @B
invoke Sleep, 1500
mov ecx, 20
@@:
push ecx
invoke Beep, 1000, 55 ;
invoke Beep, 800, 55
pop ecx
dec ecx
jnz @B
invoke ExitProcess,0
end start
Ok ,
I thought it was like magnum stated
So this is a file that comes with the computer as wav ?
For Dave:
mov esi, filebuffer
lea ebx, [esi+FileSize]
.Repeat
... ; <<<<<< I can't put the missing instruction here - you know why 8)
movzx eax, al
shl eax, 6
add eax, 127 ; be nice to your speakers
mov edx, eax
and eax, 3
invoke Beep, eax, edx
.Until esi>=ebx
I think that reasonably recreating the sound will be difficult. IIRC after the dialing sequence what you hear is the modems connecting and negotiating a bitrate.
after you hit a key, you have to wait for it to finish one pass on the loop :P
Jochen - i don't get it - lol :redface:
mov esi, filebuffer
lea ebx, [esi+FileSize]
.Repeat
... ; <<<<<< I can't put the missing instruction here - you know why 8)
movzx eax, al
shl eax, 6
add eax, 127 ; be nice to your speakers
mov edx, eax
and eax, 3
invoke Beep, eax, edx
.Until esi>=ebx
Quote from: dedndave on January 05, 2013, 10:06:05 AM
Jochen - i don't get it - lol :redface:
... ; <<<<<< I can't put the missing instruction here - you know why 8)
Starts like lol and ends like "banned by Hutch" :biggrin:
And it works - test it!
ohhhhhhhhhhhhhhhhh
i get it :biggrin:
he'd love some of my old 16-bit code - lol
i used to use LODSB, STOSB and LOOP like crazy to parse the command line
; mlx function
;
BU0003: CBW
MOV CX,AX ;char count
MOV DL,AH ;nybble flag
MOV BX,300Ah ;10/'0'
MOV DI,OFS BU0000 ;CS:0100
;
; start off in hex mode
;
BU0004: LODSB
MOV DH,AL ;save original
XOR AL,BH ;pay attention
CMP AL,BL ;is it 0-9 ?
JB BU0005
;
AND AL,0DFh ;lower case
SUB AL,51h ;(xor'ed 30h)
CMP AL,5 ;is it a-f ?
JA BU0010 ;no - test literal
;
ADD AL,BL ;yes - adjust it
;
BU0005: OR DL,DL ;first nybble ?
JZ BU0009
;
SHL AH,1 ;no - X 16
SHL AH,1
SHL AH,1
SHL AH,1
OR AL,AH ;code byte
STOSB
DEC DX ;clear nybble
;
BU0006: LOOP BU0004
;
BU0007: CMP DI,OFS BU0000 ;was there any ?
JZ BU0002 ;no - date/time
;
; all done - execute the script
;
BU0008: MOV AX,98B4h ;align IP
STOSW
STOSW
STOSW
MOV AH,4Ch ;exit with code
STOSW
MOV AX,21CDh ;INT 21h
STOSW
MOV AX,2000h ;no parsed parms
MOV CLPRM0,AX
MOV CLPRM1,AX
MOV AH,0Dh ;cr
MOV CLTAIL,AX ;no tail
MOV CLTAIL+2,OFS PRGEND
MOV AX,CX ;zero registers
MOV BX,AX
MOV DX,AX
MOV BP,AX
MOV SI,AX
MOV DI,AX
JMP BU0000 ;hope it works
;
BU0009: MOV AH,AL ;first nybble
INC DX ;set flag
LOOP BU0004
;
STOSB
JMP BU0008
;
; literal mode
;
BU0010: OR DL,DL
JZ BU0011
;
MOV AL,AH
STOSB
DEC DX
;
BU0011: CMP DH,27h ;single quote
JZ BU0013
;
CMP DH,22h ;double quote
JZ BU0013
;
LOOP BU0004
;
JMP BU0007
;
BU0012: LODSB
CMP AL,DH
JZ BU0006
;
STOSB
;
BU0013: LOOP BU0012
;
JMP BU0007
Dave,
You can convert that to an .mp3 and shrink that exe.
We don't want no VB sized code. :t
hey - it's a resource, not code :biggrin:
i may play with the wav - cut it down to a shorter loop
but - it isn't as easy to run an mp3 as it is a wav file
i can make a smaller wav by reducing the bit-rate
not like it has to be high fidelity - it's a bunch of harmonic noise, to start with
Quote from: Magnum on January 05, 2013, 12:18:23 PM
Dave,
You can convert that to an .mp3 and shrink that exe.
We don't want no VB sized code. :t
It is not that big LOL
I posted an example of how to play mp3 from resource here :
http://masm32.com/board/index.php?topic=639.msg5216#msg5216
Quote from: jj2007 on January 05, 2013, 11:33:10 AM
Quote from: dedndave on January 05, 2013, 10:06:05 AM
Jochen - i don't get it - lol :redface:
... ; <<<<<< I can't put the missing instruction here - you know why 8)
Starts like lol and ends like "banned by Hutch" :biggrin:
And it works - test it!
I like the way you show how long the putter being running
Do you have the source for that?
With out masm basic?
Quote from: hfheatherfox07 on January 05, 2013, 06:58:31 PM
I like the way you show how long the putter being running
Do you have the source for that?
With out masm basic?
Heather,
These are business secrets that are thoroughly hidden in \Masm32\MasmBasic\MasmBasic.inc but for you I will reveal them here:
Timer textequ <TimerMac(@Line)>
TimerMac MACRO MacLine
if MacLine ne MacLineTimer
MacLineTimer = MacLine
push ecx
invoke GetTickCount
pop ecx
endif
EXITM <eax>
ENDMUsage:
Inkey Str$("\n\nYour puter has run %3f hours since the last boot, give it a break!", Timer/3600000)
:biggrin:
@ jj2007
I figured this would not work for me :(
Console version ( I prefer message box ) :
TITLE Puter Run Time [MASM] (Puter.asm)
; Description: Generic Win32 Console Application Template
;
; Revision date:
comment * ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
Build this as console app
¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤ *
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\include\windows.inc ; main windows include file
include \masm32\include\masm32.inc ; masm32 library include
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\kernel32.inc
include \masm32\include\msvcrt.inc
include \masm32\include\dialogs.inc ; macro file for dialogs
includelib \masm32\lib\masm32.lib ; masm32 static library
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
include \masm32\macros\macros.asm ; masm32 macro file
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
TimerMac MACRO MacLine
if MacLine ne MacLineTimer
MacLineTimer = MacLine
push ecx
invoke GetTickCount
pop ecx
endif
EXITM <eax>
ENDM
.const
Timer textequ <TimerMac(@Line)>
.data ; Initialized data section
ConsoleTitle db "Puter Run Time:",0
.code
; Execution begins here...
start:
call main
inkey ; wait for a keystroke before exiting
exit
main proc
invoke SetConsoleTitle, ADDR ConsoleTitle
print "Your puter has run %3f hours since the last boot, give it a break!",13,10 ; Timer/3600000
ret
main endp
end start
and message Box Version :
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
TimerMac MACRO MacLine
if MacLine ne MacLineTimer
MacLineTimer = MacLine
push ecx
invoke GetTickCount
pop ecx
endif
EXITM <eax>
ENDM
.const
Timer textequ <TimerMac(@Line)>
.data
MsgCaption db "Puter Run Time:",0
MsgBoxText db "Your puter has run %3f hours since the last boot, give it a break!",0
.data?
Buffer db 256 dup (?) ; for file size..
.code
.code
start:
invoke TimerMac, ADDR Buffer
invoke wsprintf, addr Buffer, addr MsgBoxText, eax
invoke MessageBox, NULL, addr Buffer, addr MsgCaption, MB_OK
invoke ExitProcess,NULL
end start
I get Errors:
: error A2006: undefined symbol : MacLineTimer
: error A2148: invalid symbol type in expression : TimerMac
@ jj2007 Here is another console attempt... :(
That why I asked if this was with out masmBasic :( Too Dificult for me :(
TITLE Puter Run Time [MASM] (Puter.asm)
; Description: Generic Win32 Console Application Template
;
; Revision date:
comment * ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
Build this as console app
¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤ *
; ¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤=÷=¤
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
TimerMac MACRO MacLine
if MacLine ne MacLineTimer
MacLineTimer = MacLine
push ecx
invoke GetTickCount
pop ecx
endif
EXITM <eax>
ENDM
.const
Timer textequ <TimerMac(@Line)>
.data ; Initialized data section
ConsoleTitle db "Puter Run Time:",0
.code
; Execution begins here...
start:
call main
inkey ; wait for a keystroke before exiting
exit
main proc
LOCAL MacLineTimer :DWORD
LOCAL Time : DWORD
invoke SetConsoleTitle, ADDR ConsoleTitle
mov Time, rv(Timer/3600000) ; use "TimerMac" procedure
print "Your puter has run "
print str$(Time)," hours since the last boot, give it a break!",13,10 ; display the results
ret
main endp
end start
Well Technically GetTickCount does that :
The GetTickCount function retrieves the number of milliseconds that have elapsed since Windows was started.
DWORD GetTickCount(VOID)
Parameters
This function has no parameters.
Return Values
If the function succeeds, the return value is the number of milliseconds that have elapsed since Windows was started.
Remarks
The elapsed time is stored as a DWORD value. Therefore, the time will wrap around to zero if Windows is run continuously for 49.7 days.
But the time is in milliseconds....
I have a proc to convert , But I forgot where ?
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
szTitle db "Puter Run Time:",0
szformat db "%lu",0 ; time mask
.data?
buftime dd ?
db 4096 dup(?)
.code
start:
invoke GetTickCount
invoke wsprintf, addr buftime,addr szformat,eax
invoke MessageBox,0,addr buftime,addr szTitle,MB_OK
invoke ExitProcess,0
end start
No Idea how you converted Milliseconds to hours :(
I know of this but can not get it to work?
xor eax, eax
mov ax, mytime.wMilliseconds
movzx ebx, mytime.wSecond
movzx ecx, mytime.wMinute
movzx edx, mytime.wHour
movzx edi, mytime.wDay
movzx esi, mytime.wMonth
Quote from: hfheatherfox07 on January 05, 2013, 10:24:12 PM
No Idea how you converted Milliseconds to hours :(
See attachment. GetTickCount is milliseconds since boot, divide by 1000*3600 and you arrive at hours.
I found this thread http://www.masmforum.com/board/index.php?PHPSESSID=786dd40408172108b65a5a36b09c88c0&topic=8647.0
I wish I can get your example to work LOL
i have played with modems more than i wanted to - lol
mostly satellite data modems - not the same thing, really
but, i never really got into the audio interface part of a telephone modem
i think they use a few special tones at start-up to negotiate speed, etc
after that, it's probably a form of FSK, using 2 distinct tones
it sounds like more tones because of the sidebands that are generated
so, you could just alternate between 800 and 1200 Hz and just vary the duration
small durations like 1 to 5 mS seem likely
let me play with it a little...
that isn't too far off :P
you need a better random generator, but it gives you a place to start
loop00: INVOKE GetTickCount
and eax,0Fh
INVOKE Beep,800,eax
INVOKE GetTickCount
and eax,0Fh
INVOKE Beep,1200,eax
call crt__kbhit
or eax,eax
jz loop00
call crt__getch
INVOKE ExitProcess,0
Quote from: jj2007 on January 05, 2013, 10:31:08 PM
Quote from: hfheatherfox07 on January 05, 2013, 10:24:12 PM
No Idea how you converted Milliseconds to hours :(
See attachment. GetTickCount is milliseconds since boot, divide by 1000*3600 and you arrive at hours.
Thanks jj2007 Got It :t
How did you format it to get 2.7 hours for example ?
Mine shows to the nearest hour only!
Do I need to calculate for minutes too ?
.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
MsgCaption db "PUTER TIME",0
format db "Your puter has run %d:hours since the last boot, give it a break!",0
.data?
Buffer db 1024 dup (?)
szHoursVal dword ?
.code
start:
invoke GetTickCount
;Hours
mov szHoursVal,eax ; store the result of GetTickCount in eax
mov ebx,3600000
sub edx, edx ;set edx to zero
div ebx
invoke wsprintf,addr Buffer,addr format, eax
invoke MessageBox, NULL, addr Buffer, addr MsgCaption, MB_ICONASTERISK
invoke ExitProcess,NULL
end start
Quote from: dedndave on January 05, 2013, 11:14:59 PM
that isn't too far off :P
you need a better random generator, but it gives you a place to start
It is 8:04 AM I think I Will go to sleep with some soothing modem sounds :lol:
here is how it sounds with a little better random generator
you could try tone pairs other than 800 and 1200 Hz
@dedndave
you seem to enjoy this beep stuff ....
I found a MorseCode example you might like :biggrin:
Kýsa-dit.wav is Short Dit
Uzun-dit.wav is Long Dit
KDit equ 2003
UDit equ 2004
The English change if you want is
SDit equ 2003
LDit equ 2003
Snippet:
invoke PlaySound,LDit,hInstance,SND_RESOURCE
jmp short stimer
s_psg:
invoke PlaySound,SDit,hInstance,SND_RESOURCE
thanks - it's funny you mention that :biggrin:
i would like to find a way to play a MIDI sound from memory
i think it can be done, i just need to spend some time playing with the "mci" functions
that way, i can create variable-length, variable-pitch dits and dahs on the fly
Quote from: dedndave on January 14, 2013, 09:00:08 AM
thanks - it's funny you mention that :biggrin:
i would like to find a way to play a MIDI sound from memory
i think it can be done, i just need to spend some time playing with the "mci" functions
that way, i can create variable-length, variable-pitch dits and dahs on the fly
(Musical Instrument Digital InterfaceStandard) MIDI Files ("SMF" or *.mid files)
I am confused ? Do you mean play .mid ?
If by from memory you mean from res , that is easy ... I have a felling that is not what you mean from memory
yes - a .MID file - only from memory, not from a file
all the examples i have seen create a file from resource, then play it from the file
i want to play it directly from a memory buffer
EDIT - it may be that i just need to send tone information, not an actual MID format
Quote from: dedndave on January 14, 2013, 09:17:34 AM
i want to play it directly from a memory buffer
QuoteCheck the MIDIplyr sample (http://digsys20-27.pip.digsys.bg/install/vs%206%20%20%20%200/cd2/samples/vc98/SDK/GRAPHICS/AUDIO/MIDIPLYR/MIDIPLYR.C) in VC6. If I remember correctly it plays out of a file buffer.
There is also some stuff here (http://cdserv1.wbut.ac.in/81-203-2165-0/msdn_vcb/samples/vc98/sdk/graphics/audio/midiplyr/).
Warning "this code requires Windows '95" ;-)
Have you seen the example by William F. Cravener 5/27/2003 ?
Plays an mid you select .... Doesn't that have to buffer it some where to achieve that ?
file mapping - that's a thought :P
I have an example that plays an xm.inc file when you do it that way ... you play from memory
So instead of:
invoke uFMOD_PlaySong,400,hInstance,XM_RESOURCE
you use:
INVOKE uFMOD_PlaySong,addr table,XMSize,XM_MEMORY
Would that help you in anyway ? both .xm and .mid use ufmod.lib and I have the asm for that
well - i would rather learn how to do it without someone's library :P
i think this is the answer...
QuoteApplications that access memory buffers to store and access MIDI data can use the memory
I/O features of the multimedia input/output (MMIO) file services. This technique consists of
opening a memory file using mmioOpen. mmioOpen has a pointer to the buffer of MIDI data
as a parameter. This buffer can then be operated on by MCI and MMIO as if it were a file.
http://www.warpspeed.com.au/cgi-bin/inf2html.cmd?..\html\book\Toolkt40\MMAPG.INF+90 (http://www.warpspeed.com.au/cgi-bin/inf2html.cmd?..%5Chtml%5Cbook%5CToolkt40%5CMMAPG.INF+90)
i'll play with it more, when i have some time
that could also be the answer to the vista beep issue :P
i think i almost have this figured out
one line of C code is giving me trouble :P
Quote{
/* variable for IOProc */
PMMIOPROC pIOProc;
HMODULE hModMidiio;
/* variables for memory file */
MMIOINFO mmioInfo;
CHAR UserBuffer[SIZE_OF_BUFFER];
HMMIO hmmio;
/* variables for MCI commands */
MCI_OPEN_PARMS mop;
MCI_PLAY_PARMS mpp;
/* Open memory file. Provide MIDI-filled data buffer to MMIO, so
* data buffer becomes file image in memory. Also specify that
* the data will need to be translated.
*/
mmioInfo.pchBuffer = UserBuffer; /* Filled with untranslated
MIDI data */
mmioInfo.cchBuffer = SIZE_OF_BUFFER; /* User-defined */
mmioInfo.ulTranslate = MMIO_TRANSLATEDATA | MMIO_TRANSLATEHEADER;
/* Need to translate data */
mmioInfo.fccIOProc = mmioFOURCC( 'M', 'I', 'D', 'I');/* Data
format */
mmioMemInfo.fccChildIOProc = FOURCC_MEM; /* Storage type */
hmmio = mmioOpen ( NULL, mmioInfo, MMIO_READWRITE );
/* open MIDI device */
mop.pszElementName = (PSZ) hmmiomem;
mciSendCommand(
0, /* We don't know the device yet. */
MCI_OPEN, /* MCI message */
MCI_WAIT | MCI_OPEN_MMIO |
MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE,
(ULONG) &mop, /* Parameters for the message */
0 ); /* Parameter for notify message */
/* play MIDI memory file for 1 second */
mpp.ulFrom=0;
mpp.ulTo=3000; /* default is MMTIME units (1/3000 second) */
mciSendCommand(
mop.usDeviceID, /* Device to play the data */
MCI_PLAY, /* MCI message */
MCI_WAIT |
MCI_FROM | MCI_TO, /* Flags for the MCI message * /
( ULONG ) &mpp , / * Parameters for the message * /
0 ) ; / * No parm necessary * /
/ * close device * /
mciSendCommand (
mop . usDeviceID , / * Device to play this * /
MCI _ CLOSE , / * MCI message * /
MCI _ WAIT , / * Flags for the MCI message * /
( ULONG ) NULL , / * Parameters for the message * /
( ULONG ) NULL ) ; / * Parameter for notify message * /
}
(PSZ) hmmiomem
PSZ sounds like a pointer to a zero terminated something
hmmiomem sounds like a handle
i don't think this code was ever tested :P
i also think it was written for OS/2 - lol
Well I wont pretend to understand it but if you look at the playwav.cpp here :
http://www.pudn.com/downloads159/sourcecode/multimedia/mpeg/detail708927.html
Here is the README.1ST : http://read.pudn.com/downloads159/sourcecode/multimedia/mpeg/708927/README.1ST__.htm
you will see what is needed ....
Command-line parameters -p, -n, -t, -b are specific for OS/2 - use them!
You should have OS/2 Warp with MMPM installed supported DART and an audio card
capable of 44.1kHz 16 bit output.
Here is the file in case it helps :(
This actually was tested and been around since 02.12.97 ( at least when the file was uploaded lol)
mapl2135.ZIP MaPlay for OS/2 (maplay/2) version 1.3.5. MaPlay is a mpeg audio player.
yah - that's for OS/2, as well - lol
i may be able to make this work if i play with the flags
i will work on it, later :P
i think i figured out what "(PSZ) hmmiomem" means
they had to type the handle as a pointer to a null-terminated string in order to put it in the structure :P
the code is for OS/2
which is why the mciSendCommand function has 5 parameters, instead of 4
the last parm can be discarded
they moved that into the structure(s)
so - that leaves me with flags to play with - some of them may not apply for win32
i think we can scrap that method - lol
there are just too many differences between OS/2 and win32, when it comes to mci functions
but - i still think there's a way to do it
there are a lot of functions in there that don't seem to be well understood
it's a matter of taking the time to figure out how they all work - lol
i see it as a lot of unexplored territory
programmers find other ways to do it - and don't explore further