Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
PUAE
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
PocketInsanity
PUAE
Commits
c130c99e
Commit
c130c99e
authored
Aug 05, 2010
by
Mustafa 'GnoStiC' TUFAN
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
syncing 2.3.0
parent
4074da44
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1910 additions
and
0 deletions
+1910
-0
blkdev_cdimage.c
src/blkdev_cdimage.c
+1686
-0
inprec.c
src/inprec.c
+224
-0
No files found.
src/blkdev_cdimage.c
0 → 100755
View file @
c130c99e
/*
* UAE
*
* CD image file support
*
* - iso (2048/2352 block size)
* - cue/bin, cue/bin/wav, cue/bin/mp3
* - ccd/img and ccd/img/sub
*
* Copyright 2010 Toni Wilen
*
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include "options.h"
#include "blkdev.h"
#include "zfile.h"
#include "gui.h"
#include "fsdb.h"
#include "threaddep/thread.h"
#include "scsidev.h"
#include <mp3decoder.h>
#include <memory.h>
#ifdef RETROPLATFORM
#include "rp.h"
#endif
#define scsi_log write_log
#define CDDA_BUFFERS 6
enum
audenc
{
AUDENC_NONE
,
AUDENC_PCM
,
AUDENC_MP3
,
AUDENC_FLAC
};
struct
cdtoc
{
struct
zfile
*
handle
;
int
offset
;
uae_u8
*
data
;
struct
zfile
*
subhandle
;
int
suboffset
;
uae_u8
*
subdata
;
int
filesize
;
TCHAR
*
fname
;
int
address
;
uae_u8
adr
,
ctrl
;
int
track
;
int
size
;
int
skipsize
;
// bytes to skip after each block
audenc
enctype
;
int
writeoffset
;
int
subcode
;
};
struct
cdunit
{
bool
enabled
;
bool
open
;
uae_u8
buffer
[
2352
];
struct
cdtoc
toc
[
102
];
int
tracks
;
uae_u64
cdsize
;
int
blocksize
;
int
cdda_play_finished
;
int
cdda_play
;
int
cdda_paused
;
int
cdda_volume
[
2
];
int
cdda_scan
;
int
cd_last_pos
;
int
cdda_start
,
cdda_end
;
play_subchannel_callback
cdda_subfunc
;
bool
slowunit
;
int
imagechange
;
TCHAR
newfile
[
MAX_DPATH
];
uae_sem_t
sub_sem
;
struct
device_info
di
;
};
static
struct
cdunit
cdunits
[
MAX_TOTAL_SCSI_DEVICES
];
static
int
bus_open
;
static
volatile
int
cdimage_unpack_thread
,
cdimage_unpack_active
;
static
smp_comm_pipe
unpack_pipe
;
static
struct
cdunit
*
unitisopen
(
int
unitnum
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
unitnum
];
if
(
cdu
->
open
)
return
cdu
;
return
NULL
;
}
static
struct
cdtoc
*
findtoc
(
struct
cdunit
*
cdu
,
int
*
sectorp
)
{
int
i
;
int
sector
;
sector
=
*
sectorp
;
for
(
i
=
0
;
i
<=
cdu
->
tracks
;
i
++
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
i
];
if
(
t
->
address
>
sector
)
{
if
(
i
==
0
)
{
*
sectorp
=
0
;
return
t
;
}
t
--
;
sector
-=
t
->
address
;
*
sectorp
=
sector
;
return
t
;
}
}
return
NULL
;
}
// WOHOO, library that supports virtual file access functions. Perfect!
static
void
flac_metadata_callback
(
const
FLAC__StreamDecoder
*
decoder
,
const
FLAC__StreamMetadata
*
metadata
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
if
(
t
->
data
)
return
;
if
(
metadata
->
type
==
FLAC__METADATA_TYPE_STREAMINFO
)
{
t
->
filesize
=
metadata
->
data
.
stream_info
.
total_samples
*
(
metadata
->
data
.
stream_info
.
bits_per_sample
/
8
)
*
metadata
->
data
.
stream_info
.
channels
;
}
}
static
void
flac_error_callback
(
const
FLAC__StreamDecoder
*
decoder
,
FLAC__StreamDecoderErrorStatus
status
,
void
*
client_data
)
{
return
;
}
static
FLAC__StreamDecoderWriteStatus
flac_write_callback
(
const
FLAC__StreamDecoder
*
decoder
,
const
FLAC__Frame
*
frame
,
const
FLAC__int32
*
const
buffer
[],
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
uae_u16
*
p
=
(
uae_u16
*
)(
t
->
data
+
t
->
writeoffset
);
int
size
=
4
;
for
(
int
i
=
0
;
i
<
frame
->
header
.
blocksize
&&
t
->
writeoffset
<
t
->
filesize
-
size
;
i
++
,
t
->
writeoffset
+=
size
)
{
*
p
++
=
(
FLAC__int16
)
buffer
[
0
][
i
];
*
p
++
=
(
FLAC__int16
)
buffer
[
1
][
i
];
}
return
FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE
;
}
static
FLAC__StreamDecoderReadStatus
file_read_callback
(
const
FLAC__StreamDecoder
*
decoder
,
FLAC__byte
buffer
[],
size_t
*
bytes
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
if
(
zfile_ftell
(
t
->
handle
)
>=
zfile_size
(
t
->
handle
))
return
FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
;
return
zfile_fread
(
buffer
,
*
bytes
,
1
,
t
->
handle
)
?
FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
:
FLAC__STREAM_DECODER_READ_STATUS_ABORT
;
}
static
FLAC__StreamDecoderSeekStatus
file_seek_callback
(
const
FLAC__StreamDecoder
*
decoder
,
FLAC__uint64
absolute_byte_offset
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
zfile_fseek
(
t
->
handle
,
absolute_byte_offset
,
SEEK_SET
);
return
FLAC__STREAM_DECODER_SEEK_STATUS_OK
;
}
static
FLAC__StreamDecoderTellStatus
file_tell_callback
(
const
FLAC__StreamDecoder
*
decoder
,
FLAC__uint64
*
absolute_byte_offset
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
*
absolute_byte_offset
=
zfile_ftell
(
t
->
handle
);
return
FLAC__STREAM_DECODER_TELL_STATUS_OK
;
}
static
FLAC__StreamDecoderLengthStatus
file_len_callback
(
const
FLAC__StreamDecoder
*
decoder
,
FLAC__uint64
*
stream_length
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
*
stream_length
=
zfile_size
(
t
->
handle
);
return
FLAC__STREAM_DECODER_LENGTH_STATUS_OK
;
}
static
FLAC__bool
file_eof_callback
(
const
FLAC__StreamDecoder
*
decoder
,
void
*
client_data
)
{
struct
cdtoc
*
t
=
(
struct
cdtoc
*
)
client_data
;
return
zfile_ftell
(
t
->
handle
)
>=
zfile_size
(
t
->
handle
);
}
static
void
flac_get_size
(
struct
cdtoc
*
t
)
{
FLAC__StreamDecoder
*
decoder
=
FLAC__stream_decoder_new
();
if
(
decoder
)
{
FLAC__stream_decoder_set_md5_checking
(
decoder
,
false
);
int
init_status
=
FLAC__stream_decoder_init_stream
(
decoder
,
&
file_read_callback
,
&
file_seek_callback
,
&
file_tell_callback
,
&
file_len_callback
,
&
file_eof_callback
,
&
flac_write_callback
,
&
flac_metadata_callback
,
&
flac_error_callback
,
t
);
FLAC__stream_decoder_process_until_end_of_metadata
(
decoder
);
FLAC__stream_decoder_delete
(
decoder
);
}
}
static
uae_u8
*
flac_get_data
(
struct
cdtoc
*
t
)
{
write_log
(
"FLAC: unpacking '%s'..
\n
"
,
zfile_getname
(
t
->
handle
));
t
->
writeoffset
=
0
;
FLAC__StreamDecoder
*
decoder
=
FLAC__stream_decoder_new
();
if
(
decoder
)
{
FLAC__stream_decoder_set_md5_checking
(
decoder
,
false
);
int
init_status
=
FLAC__stream_decoder_init_stream
(
decoder
,
&
file_read_callback
,
&
file_seek_callback
,
&
file_tell_callback
,
&
file_len_callback
,
&
file_eof_callback
,
&
flac_write_callback
,
&
flac_metadata_callback
,
&
flac_error_callback
,
t
);
FLAC__stream_decoder_process_until_end_of_stream
(
decoder
);
FLAC__stream_decoder_delete
(
decoder
);
write_log
(
"FLAC: %s unpacked
\n
"
,
zfile_getname
(
t
->
handle
));
}
return
t
->
data
;
}
#ifdef _WIN32
static
HWAVEOUT
cdda_wavehandle
;
static
void
cdda_closewav
(
void
)
{
if
(
cdda_wavehandle
!=
NULL
)
waveOutClose
(
cdda_wavehandle
);
cdda_wavehandle
=
NULL
;
}
static
int
cdda_openwav
(
void
)
{
WAVEFORMATEX
wav
=
{
0
};
MMRESULT
mmr
;
wav
.
cbSize
=
0
;
wav
.
nChannels
=
2
;
wav
.
nSamplesPerSec
=
44100
;
wav
.
wBitsPerSample
=
16
;
wav
.
nBlockAlign
=
wav
.
wBitsPerSample
/
8
*
wav
.
nChannels
;
wav
.
nAvgBytesPerSec
=
wav
.
nBlockAlign
*
wav
.
nSamplesPerSec
;
wav
.
wFormatTag
=
WAVE_FORMAT_PCM
;
mmr
=
waveOutOpen
(
&
cdda_wavehandle
,
WAVE_MAPPER
,
&
wav
,
0
,
0
,
WAVE_ALLOWSYNC
|
WAVE_FORMAT_DIRECT
);
if
(
mmr
!=
MMSYSERR_NOERROR
)
{
write_log
(
"IMAGE CDDA: wave open %d
\n
"
,
mmr
);
cdda_closewav
();
return
0
;
}
return
1
;
}
static
void
sub_to_interleaved
(
const
uae_u8
*
s
,
uae_u8
*
d
)
{
for
(
int
i
=
0
;
i
<
8
*
12
;
i
++
)
{
int
dmask
=
0x80
;
int
smask
=
1
<<
(
7
-
(
i
&
7
));
(
*
d
)
=
0
;
for
(
int
j
=
0
;
j
<
8
;
j
++
)
{
(
*
d
)
|=
(
s
[(
i
/
8
)
+
j
*
12
]
&
smask
)
?
dmask
:
0
;
dmask
>>=
1
;
}
d
++
;
}
}
static
void
sub_to_deinterleaved
(
const
uae_u8
*
s
,
uae_u8
*
d
)
{
for
(
int
i
=
0
;
i
<
8
*
12
;
i
++
)
{
int
dmask
=
0x80
;
int
smask
=
1
<<
(
7
-
(
i
/
12
));
(
*
d
)
=
0
;
for
(
int
j
=
0
;
j
<
8
;
j
++
)
{
(
*
d
)
|=
(
s
[(
i
%
12
)
*
8
+
j
]
&
smask
)
?
dmask
:
0
;
dmask
>>=
1
;
}
d
++
;
}
}
static
int
getsub
(
uae_u8
*
dst
,
struct
cdunit
*
cdu
,
struct
cdtoc
*
t
,
int
sector
)
{
int
ret
=
0
;
uae_sem_wait
(
&
cdu
->
sub_sem
);
if
(
t
->
subcode
)
{
if
(
t
->
subhandle
)
{
int
offset
=
0
;
int
totalsize
=
SUB_CHANNEL_SIZE
;
if
(
t
->
skipsize
)
{
totalsize
+=
t
->
size
;
offset
=
t
->
size
;
}
zfile_fseek
(
t
->
subhandle
,
sector
*
totalsize
+
t
->
suboffset
+
offset
,
SEEK_SET
);
if
(
zfile_fread
(
dst
,
SUB_CHANNEL_SIZE
,
1
,
t
->
subhandle
)
>
0
)
ret
=
t
->
subcode
;
}
else
{
memcpy
(
dst
,
t
->
subdata
+
sector
*
SUB_CHANNEL_SIZE
+
t
->
suboffset
,
SUB_CHANNEL_SIZE
);
ret
=
t
->
subcode
;
}
}
if
(
!
ret
)
{
memset
(
dst
,
0
,
SUB_CHANNEL_SIZE
);
// regenerate Q-subchannel
uae_u8
*
s
=
dst
+
12
;
s
[
0
]
=
(
t
->
ctrl
<<
4
)
|
(
t
->
adr
<<
0
);
s
[
1
]
=
tobcd
(
t
-
&
cdu
->
toc
[
0
]
+
1
);
s
[
2
]
=
tobcd
(
1
);
int
msf
=
lsn2msf
(
sector
);
tolongbcd
(
s
+
7
,
msf
);
msf
=
lsn2msf
(
sector
-
t
->
address
-
150
);
tolongbcd
(
s
+
3
,
msf
);
ret
=
2
;
}
if
(
ret
==
1
)
{
uae_u8
tmp
[
SUB_CHANNEL_SIZE
];
memcpy
(
tmp
,
dst
,
SUB_CHANNEL_SIZE
);
sub_to_deinterleaved
(
tmp
,
dst
);
ret
=
2
;
}
uae_sem_post
(
&
cdu
->
sub_sem
);
return
ret
;
}
static
void
dosub
(
struct
cdunit
*
cdu
,
struct
cdtoc
*
t
,
int
sector
)
{
uae_u8
*
d
;
uae_u8
subbuf
[
SUB_CHANNEL_SIZE
];
uae_u8
subbuf2
[
SUB_CHANNEL_SIZE
];
if
(
!
cdu
->
cdda_subfunc
)
return
;
if
(
!
t
)
{
memset
(
subbuf
,
0
,
sizeof
subbuf
);
cdu
->
cdda_subfunc
(
subbuf
,
1
);
return
;
}
memset
(
subbuf
,
0
,
SUB_CHANNEL_SIZE
);
int
mode
=
getsub
(
subbuf
,
cdu
,
t
,
sector
);
if
(
mode
==
2
)
{
// deinterleaved -> interleaved
sub_to_interleaved
(
subbuf
,
subbuf2
);
d
=
subbuf2
;
}
else
{
d
=
subbuf
;
}
cdu
->
cdda_subfunc
(
d
,
1
);
}
static
void
*
cdda_unpack_func
(
void
*
v
)
{
cdimage_unpack_thread
=
1
;
mp3decoder
*
mp3dec
=
NULL
;
for
(;;)
{
uae_u32
cduidx
=
read_comm_pipe_u32_blocking
(
&
unpack_pipe
);
if
(
cdimage_unpack_thread
==
0
)
break
;
uae_u32
tocidx
=
read_comm_pipe_u32_blocking
(
&
unpack_pipe
);
struct
cdunit
*
cdu
=
&
cdunits
[
cduidx
];
struct
cdtoc
*
t
=
&
cdu
->
toc
[
tocidx
];
if
(
t
->
handle
)
{
// force unpack if handle points to delayed zipped file
uae_s64
pos
=
zfile_ftell
(
t
->
handle
);
zfile_fseek
(
t
->
handle
,
-
1
,
SEEK_END
);
uae_u8
b
;
zfile_fread
(
&
b
,
1
,
1
,
t
->
handle
);
zfile_fseek
(
t
->
handle
,
pos
,
SEEK_SET
);
if
(
!
t
->
data
&&
(
t
->
enctype
==
AUDENC_MP3
||
t
->
enctype
==
AUDENC_FLAC
))
{
t
->
data
=
xcalloc
(
uae_u8
,
t
->
filesize
+
2352
);
cdimage_unpack_active
=
1
;
if
(
t
->
data
)
{
if
(
t
->
enctype
==
AUDENC_MP3
)
{
if
(
!
mp3dec
)
{
try
{
mp3dec
=
new
mp3decoder
();
}
catch
(
exception
)
{
};
}
if
(
mp3dec
)
t
->
data
=
mp3dec
->
get
(
t
->
handle
,
t
->
data
,
t
->
filesize
);
}
else
if
(
t
->
enctype
==
AUDENC_FLAC
)
{
flac_get_data
(
t
);
}
}
}
}
cdimage_unpack_active
=
2
;
}
delete
mp3dec
;
cdimage_unpack_thread
=
-
1
;
return
0
;
}
static
void
*
cdda_play_func
(
void
*
v
)
{
int
cdda_pos
;
int
num_sectors
=
CDDA_BUFFERS
;
int
quit
=
0
;
int
bufnum
;
int
buffered
;
uae_u8
*
px
[
2
],
*
p
;
int
bufon
[
2
];
int
i
;
WAVEHDR
whdr
[
2
];
MMRESULT
mmr
;
int
volume
[
2
],
volume_main
;
int
oldplay
;
struct
cdunit
*
cdu
=
(
struct
cdunit
*
)
v
;
int
firstloops
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
memset
(
&
whdr
[
i
],
0
,
sizeof
(
WAVEHDR
));
whdr
[
i
].
dwFlags
=
WHDR_DONE
;
}
while
(
cdu
->
cdda_play
==
0
)
Sleep
(
10
);
oldplay
=
-
1
;
p
=
xmalloc
(
uae_u8
,
2
*
num_sectors
*
4096
);
px
[
0
]
=
p
;
px
[
1
]
=
p
+
num_sectors
*
4096
;
bufon
[
0
]
=
bufon
[
1
]
=
0
;
bufnum
=
0
;
buffered
=
0
;
volume
[
0
]
=
volume
[
1
]
=
-
1
;
volume_main
=
-
1
;
if
(
cdda_openwav
())
{
for
(
i
=
0
;
i
<
2
;
i
++
)
{
memset
(
&
whdr
[
i
],
0
,
sizeof
(
WAVEHDR
));
whdr
[
i
].
dwBufferLength
=
2352
*
num_sectors
;
whdr
[
i
].
lpData
=
(
LPSTR
)
px
[
i
];
mmr
=
waveOutPrepareHeader
(
cdda_wavehandle
,
&
whdr
[
i
],
sizeof
(
WAVEHDR
));
if
(
mmr
!=
MMSYSERR_NOERROR
)
{
write_log
(
"CDDA: waveOutPrepareHeader %d:%d
\n
"
,
i
,
mmr
);
goto
end
;
}
whdr
[
i
].
dwFlags
|=
WHDR_DONE
;
}
while
(
cdu
->
cdda_play
>
0
)
{
if
(
oldplay
!=
cdu
->
cdda_play
)
{
struct
cdtoc
*
t
;
int
sector
;
struct
_timeb
tb
;
_ftime
(
&
tb
);
cdda_pos
=
cdu
->
cdda_start
;
oldplay
=
cdu
->
cdda_play
;
cdu
->
cd_last_pos
=
cdda_pos
;
sector
=
cdu
->
cdda_start
;
t
=
findtoc
(
cdu
,
&
sector
);
if
(
!
t
)
{
write_log
(
"IMAGE CDDA: illegal sector number %d
\n
"
,
cdu
->
cdda_start
);
}
else
{
write_log
(
"IMAGE CDDA: playing from %d to %d, track %d ('%s', offset %d, secoffset %d)
\n
"
,
cdu
->
cdda_start
,
cdu
->
cdda_end
,
t
->
track
,
t
->
fname
,
t
->
offset
,
sector
);
// do this even if audio is not compressed, t->handle also could be
// compressed and we want to unpack it in background too
while
(
cdimage_unpack_active
==
1
)
Sleep
(
10
);
cdimage_unpack_active
=
0
;
write_comm_pipe_u32
(
&
unpack_pipe
,
cdu
-
&
cdunits
[
0
],
0
);
write_comm_pipe_u32
(
&
unpack_pipe
,
t
-
&
cdu
->
toc
[
0
],
1
);
while
(
cdimage_unpack_active
==
0
)
Sleep
(
10
);
}
firstloops
=
cdu
->
slowunit
?
150
:
30
;
while
(
cdu
->
cdda_paused
&&
cdu
->
cdda_play
>
0
)
{
Sleep
(
10
);
firstloops
=
-
1
;
}
if
(
firstloops
>
0
)
firstloops
/=
num_sectors
;
}
while
(
!
(
whdr
[
bufnum
].
dwFlags
&
WHDR_DONE
))
{
Sleep
(
10
);
if
(
!
cdu
->
cdda_play
)
goto
end
;
}
bufon
[
bufnum
]
=
0
;
if
(
!
isaudiotrack
(
&
cdu
->
di
.
toc
,
cdda_pos
))
goto
end
;
// data track?
if
((
cdda_pos
<
cdu
->
cdda_end
||
cdu
->
cdda_end
==
0xffffffff
)
&&
!
cdu
->
cdda_paused
&&
cdu
->
cdda_play
>
0
)
{
struct
cdtoc
*
t
;
int
sector
,
cnt
;
int
dofinish
=
0
;
gui_flicker_led
(
LED_CD
,
cdu
->
di
.
unitnum
-
1
,
LED_CD_AUDIO
);
memset
(
px
[
bufnum
],
0
,
num_sectors
*
2352
);
if
(
firstloops
>
0
)
{
firstloops
--
;
for
(
cnt
=
0
;
cnt
<
num_sectors
;
cnt
++
)
dosub
(
cdu
,
NULL
,
-
1
);
}
else
{
for
(
cnt
=
0
;
cnt
<
num_sectors
;
cnt
++
)
{
sector
=
cdda_pos
;
if
(
cdu
->
cdda_scan
)
{
cdda_pos
+=
cdu
->
cdda_scan
;
if
(
cdda_pos
<
0
)
cdda_pos
=
0
;
}
else
{
cdda_pos
++
;
}
if
(
cdda_pos
-
num_sectors
<
cdu
->
cdda_end
&&
cdda_pos
>=
cdu
->
cdda_end
)
dofinish
=
1
;
t
=
findtoc
(
cdu
,
&
sector
);
if
(
t
)
{
if
(
t
->
handle
&&
!
(
t
->
ctrl
&
4
))
{
uae_u8
*
dst
=
px
[
bufnum
]
+
cnt
*
t
->
size
;
int
totalsize
=
t
->
size
+
t
->
skipsize
;
if
((
t
->
enctype
==
AUDENC_MP3
||
t
->
enctype
==
AUDENC_FLAC
)
&&
t
->
data
)
{
if
(
t
->
filesize
>=
sector
*
totalsize
+
t
->
offset
+
t
->
size
)
memcpy
(
dst
,
t
->
data
+
sector
*
totalsize
+
t
->
offset
,
t
->
size
);
}
else
if
(
t
->
enctype
==
AUDENC_PCM
)
{
if
(
sector
*
totalsize
+
t
->
offset
+
totalsize
<
t
->
filesize
)
{
zfile_fseek
(
t
->
handle
,
sector
*
totalsize
+
t
->
offset
,
SEEK_SET
);
zfile_fread
(
dst
,
t
->
size
,
1
,
t
->
handle
);
}
}
}
dosub
(
cdu
,
t
,
cdda_pos
);
}
}
}
volume_main
=
currprefs
.
sound_volume
;
int
vol_mult
[
2
];
for
(
int
j
=
0
;
j
<
2
;
j
++
)
{
volume
[
j
]
=
cdu
->
cdda_volume
[
j
];
vol_mult
[
j
]
=
(
100
-
volume_main
)
*
volume
[
j
]
/
100
;
if
(
vol_mult
[
j
])
vol_mult
[
j
]
++
;
if
(
vol_mult
[
j
]
>=
32768
)
vol_mult
[
j
]
=
32768
;
}
uae_s16
*
p
=
(
uae_s16
*
)(
px
[
bufnum
]);
for
(
i
=
0
;
i
<
num_sectors
*
2352
/
4
;
i
++
)
{
p
[
i
*
2
+
0
]
=
p
[
i
*
2
+
0
]
*
vol_mult
[
0
]
/
32768
;
p
[
i
*
2
+
1
]
=
p
[
i
*
2
+
1
]
*
vol_mult
[
1
]
/
32768
;
}
bufon
[
bufnum
]
=
1
;
mmr
=
waveOutWrite
(
cdda_wavehandle
,
&
whdr
[
bufnum
],
sizeof
(
WAVEHDR
));
if
(
mmr
!=
MMSYSERR_NOERROR
)
{
write_log
(
"IMAGE CDDA: waveOutWrite %d
\n
"
,
mmr
);
break
;
}
cdu
->
cd_last_pos
=
cdda_pos
;
if
(
dofinish
)
{
cdu
->
cdda_play_finished
=
1
;
cdu
->
cdda_play
=
-
1
;
cdda_pos
=
cdu
->
cdda_end
+
1
;
}
}
if
(
bufon
[
0
]
==
0
&&
bufon
[
1
]
==
0
)
{
while
(
!
(
whdr
[
0
].
dwFlags
&
WHDR_DONE
)
||
!
(
whdr
[
1
].
dwFlags
&
WHDR_DONE
))
Sleep
(
10
);
while
(
cdu
->
cdda_paused
&&
cdu
->
cdda_play
>
0
)
Sleep
(
10
);
}
bufnum
=
1
-
bufnum
;
}
}
end:
while
(
!
(
whdr
[
0
].
dwFlags
&
WHDR_DONE
)
||
!
(
whdr
[
1
].
dwFlags
&
WHDR_DONE
))
Sleep
(
10
);
for
(
i
=
0
;
i
<
2
;
i
++
)
waveOutUnprepareHeader
(
cdda_wavehandle
,
&
whdr
[
i
],
sizeof
(
WAVEHDR
));
while
(
cdimage_unpack_active
==
1
)
Sleep
(
10
);
cdda_closewav
();
xfree
(
p
);
cdu
->
cdda_play
=
0
;
write_log
(
"IMAGE CDDA: thread killed
\n
"
);
return
NULL
;
}
#endif
static
void
cdda_stop
(
struct
cdunit
*
cdu
)
{
if
(
cdu
->
cdda_play
>
0
)
{
cdu
->
cdda_play
=
-
1
;
while
(
cdu
->
cdda_play
)
{
Sleep
(
10
);
}
}
cdu
->
cdda_play_finished
=
0
;
cdu
->
cdda_paused
=
0
;
}
static
int
command_pause
(
int
unitnum
,
int
paused
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
-
1
;
int
old
=
cdu
->
cdda_paused
;
cdu
->
cdda_paused
=
paused
;
return
old
;
}
static
int
command_stop
(
int
unitnum
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
cdda_stop
(
cdu
);
return
1
;
}
static
int
command_play
(
int
unitnum
,
int
startlsn
,
int
endlsn
,
int
scan
,
play_subchannel_callback
subfunc
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
if
(
!
isaudiotrack
(
&
cdu
->
di
.
toc
,
startlsn
))
return
0
;
cdu
->
cdda_play_finished
=
0
;
cdu
->
cd_last_pos
=
startlsn
;
cdu
->
cdda_start
=
startlsn
;
cdu
->
cdda_end
=
endlsn
;
cdu
->
cdda_subfunc
=
subfunc
;
cdu
->
cdda_scan
=
scan
>
0
?
10
:
(
scan
<
0
?
10
:
0
);
if
(
!
cdu
->
cdda_play
)
uae_start_thread
(
"cdimage_cdda_play"
,
cdda_play_func
,
cdu
,
NULL
);
cdu
->
cdda_play
++
;
return
1
;
}
static
int
command_qcode
(
int
unitnum
,
uae_u8
*
buf
,
int
sector
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
uae_u8
subbuf
[
SUB_CHANNEL_SIZE
];
uae_u8
*
p
;
int
trk
;
int
pos
;
int
status
;
memset
(
buf
,
0
,
SUBQ_SIZE
);
p
=
buf
;
status
=
AUDIO_STATUS_NO_STATUS
;
if
(
cdu
->
cdda_play
>
0
)
{
status
=
AUDIO_STATUS_IN_PROGRESS
;
if
(
cdu
->
cdda_paused
)
status
=
AUDIO_STATUS_PAUSED
;
}
else
if
(
cdu
->
cdda_play_finished
)
{
status
=
AUDIO_STATUS_PLAY_COMPLETE
;
}
if
(
sector
<
0
)
pos
=
cdu
->
cd_last_pos
;
else
pos
=
sector
;
p
[
1
]
=
status
;
p
[
3
]
=
12
;
p
=
buf
+
4
;
struct
cdtoc
*
td
=
NULL
;
for
(
trk
=
0
;
trk
<=
cdu
->
tracks
;
trk
++
)
{
td
=
&
cdu
->
toc
[
trk
];
if
(
pos
<
td
->
address
)
{
if
(
trk
>
0
)
td
--
;
break
;
}
if
(
pos
>=
td
->
address
&&
pos
<
td
[
1
].
address
)
break
;
}
if
(
!
td
)
return
0
;
getsub
(
subbuf
,
cdu
,
td
,
pos
);
memcpy
(
p
,
subbuf
+
12
,
12
);
// write_log ("%6d %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n",
// pos, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]);
return
1
;
}
static
uae_u32
command_volume
(
int
unitnum
,
uae_u16
volume_left
,
uae_u16
volume_right
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
-
1
;
uae_u32
old
=
(
cdu
->
cdda_volume
[
1
]
<<
16
)
|
(
cdu
->
cdda_volume
[
0
]
<<
0
);
cdu
->
cdda_volume
[
0
]
=
volume_left
;
cdu
->
cdda_volume
[
1
]
=
volume_right
;
return
old
;
}
extern
void
encode_l2
(
uae_u8
*
p
,
int
address
);
static
int
command_rawread
(
int
unitnum
,
uae_u8
*
data
,
int
sector
,
int
size
,
int
sectorsize
,
uae_u32
extra
)
{
int
ret
=
0
;
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
struct
cdtoc
*
t
=
findtoc
(
cdu
,
&
sector
);
if
(
!
t
||
t
->
handle
==
NULL
)
return
0
;
cdda_stop
(
cdu
);
if
(
sectorsize
>
0
)
{
if
(
sectorsize
==
2352
&&
t
->
size
==
2048
)
{
// 2048 -> 2352
while
(
size
--
>
0
)
{
memset
(
data
,
0
,
16
);
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
,
SEEK_SET
);
zfile_fread
(
data
+
16
,
t
->
size
,
1
,
t
->
handle
);
encode_l2
(
data
,
sector
+
150
);
sector
++
;
data
+=
sectorsize
;
}
}
else
if
(
sectorsize
==
2048
&&
t
->
size
==
2352
)
{
// 2352 -> 2048
while
(
size
--
>
0
)
{
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
+
16
,
SEEK_SET
);
zfile_fread
(
data
,
sectorsize
,
1
,
t
->
handle
);
sector
++
;
data
+=
sectorsize
;
}
}
else
if
(
sectorsize
==
2336
&&
t
->
size
==
2352
)
{
// 2352 -> 2336
while
(
size
--
>
0
)
{
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
+
16
,
SEEK_SET
);
zfile_fread
(
data
,
sectorsize
,
1
,
t
->
handle
);
sector
++
;
data
+=
sectorsize
;
}
}
else
if
(
sectorsize
==
t
->
size
)
{
// no change
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
,
SEEK_SET
);
zfile_fread
(
data
,
sectorsize
,
size
,
t
->
handle
);
sector
+=
size
;
}
cdu
->
cd_last_pos
=
sector
;
ret
=
sectorsize
*
size
;
}
else
{
uae_u8
sectortype
=
extra
>>
16
;
uae_u8
cmd9
=
extra
>>
8
;
int
sync
=
(
cmd9
>>
7
)
&
1
;
int
headercodes
=
(
cmd9
>>
5
)
&
3
;
int
userdata
=
(
cmd9
>>
4
)
&
1
;
int
edcecc
=
(
cmd9
>>
3
)
&
1
;
int
errorfield
=
(
cmd9
>>
1
)
&
3
;
uae_u8
subs
=
extra
&
7
;
if
(
subs
!=
0
&&
subs
!=
1
&&
subs
!=
2
&&
subs
!=
4
)
return
-
1
;
if
(
isaudiotrack
(
&
cdu
->
di
.
toc
,
sector
))
{
if
(
sectortype
!=
0
&&
sectortype
!=
1
)
return
-
2
;
if
(
t
->
size
!=
2352
)
return
-
1
;
for
(
int
i
=
0
;
i
<
size
;
i
++
)
{
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
,
SEEK_SET
);
zfile_fread
(
data
,
t
->
size
,
1
,
t
->
handle
);
uae_u8
*
p
=
data
+
t
->
size
;
if
(
subs
)
{
uae_u8
subdata
[
SUB_CHANNEL_SIZE
];
getsub
(
subdata
,
cdu
,
t
,
sector
);
if
(
subs
==
4
)
{
// all, de-interleaved
memcpy
(
p
,
subdata
,
SUB_CHANNEL_SIZE
);
p
+=
SUB_CHANNEL_SIZE
;
}
else
if
(
subs
==
2
)
{
// q-only
memcpy
(
p
,
subdata
+
SUB_ENTRY_SIZE
,
SUB_ENTRY_SIZE
);
p
+=
SUB_ENTRY_SIZE
;
}
else
if
(
subs
==
1
)
{
// all, interleaved
sub_to_interleaved
(
subdata
,
p
);
p
+=
SUB_CHANNEL_SIZE
;
}
}
ret
+=
p
-
data
;
data
=
p
;
sector
++
;
}
}
}
return
ret
;
}
// this only supports 2048 byte sectors
static
int
command_read
(
int
unitnum
,
uae_u8
*
data
,
int
sector
,
int
size
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
struct
cdtoc
*
t
=
findtoc
(
cdu
,
&
sector
);
int
offset
;
if
(
!
t
||
t
->
handle
==
NULL
)
return
NULL
;
cdda_stop
(
cdu
);
if
(
t
->
size
==
2048
)
{
int
offset
=
0
;
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
+
offset
,
SEEK_SET
);
zfile_fread
(
data
,
size
,
2048
,
t
->
handle
);
sector
+=
size
;
}
else
{
offset
=
16
;
zfile_fseek
(
t
->
handle
,
t
->
offset
+
sector
*
t
->
size
+
offset
,
SEEK_SET
);
zfile_fread
(
data
,
size
,
2048
,
t
->
handle
);
cdu
->
cd_last_pos
=
sector
;
return
1
;
}
static
int
command_toc
(
int
unitnum
,
struct
cd_toc_head
*
th
)
{
struct
cdunit
*
cdu
=
unitisopen
(
unitnum
);
if
(
!
cdu
)
return
0
;
int
i
;
memset
(
&
cdu
->
di
.
toc
,
0
,
sizeof
(
struct
cd_toc_head
));
if
(
!
cdu
->
tracks
)
return
0
;
memset
(
th
,
0
,
sizeof
(
struct
cd_toc_head
));
struct
cd_toc
*
toc
=
&
th
->
toc
[
0
];
th
->
first_track
=
1
;
th
->
last_track
=
cdu
->
tracks
;
th
->
points
=
cdu
->
tracks
+
3
;
th
->
tracks
=
cdu
->
tracks
;
th
->
lastaddress
=
cdu
->
toc
[
cdu
->
tracks
].
address
;
toc
->
adr
=
1
;
toc
->
point
=
0xa0
;
toc
->
track
=
th
->
first_track
;
toc
++
;
th
->
first_track_offset
=
1
;
for
(
i
=
0
;
i
<
cdu
->
tracks
;
i
++
)
{
toc
->
adr
=
cdu
->
toc
[
i
].
adr
;
toc
->
control
=
cdu
->
toc
[
i
].
ctrl
;
toc
->
track
=
i
+
1
;
toc
->
point
=
i
+
1
;
toc
->
paddress
=
cdu
->
toc
[
i
].
address
;
toc
++
;
}
th
->
last_track_offset
=
cdu
->
tracks
;
toc
->
adr
=
1
;
toc
->
point
=
0xa1
;
toc
->
track
=
th
->
last_track
;
toc
++
;
toc
->
adr
=
1
;
toc
->
point
=
0xa2
;
toc
->
paddress
=
th
->
lastaddress
;
toc
++
;
memcpy
(
&
cdu
->
di
.
toc
,
th
,
sizeof
(
struct
cd_toc_head
));
gui_flicker_led
(
LED_CD
,
unitnum
,
1
);
return
1
;
}
static
void
skipspace
(
TCHAR
**
s
)
{
while
(
_istspace
(
**
s
))
(
*
s
)
++
;
}
static
void
skipnspace
(
TCHAR
**
s
)
{
while
(
!
_istspace
(
**
s
))
(
*
s
)
++
;
}
static
TCHAR
*
nextstring
(
TCHAR
**
sp
)
{
TCHAR
*
s
;
TCHAR
*
out
=
NULL
;
skipspace
(
sp
);
s
=
*
sp
;
if
(
*
s
==
'\"'
)
{
s
++
;
out
=
s
;
while
(
*
s
&&
*
s
!=
'\"'
)
s
++
;
*
s
++
=
0
;
}
else
if
(
*
s
)
{
out
=
s
;
skipnspace
(
&
s
);
*
s
++
=
0
;
}
*
sp
=
s
;
return
out
;
}
static
int
readval
(
const
TCHAR
*
s
)
{
int
base
=
10
;
TCHAR
*
endptr
;
if
(
s
[
0
]
==
'0'
&&
_totupper
(
s
[
1
])
==
'X'
)
s
+=
2
,
base
=
16
;
return
_tcstol
(
s
,
&
endptr
,
base
);
}
#define MEDIA_DESCRIPTOR "MEDIA DESCRIPTOR"
/* MDS spec structures from cdemu */
#define MDS_MEDIUM_CD 0x00
/* CD-ROM */
#define MDS_MEDIUM_CD_R 0x01
/* CD-R */
#define MDS_MEDIUM_CD_RW 0x02
/* CD-RW */
#define MDS_MEDIUM_DVD 0x10
/* DVD-ROM */
#define MDS_MEDIUM_DVD_MINUS_R 0x12
/* DVD-R */
#define MDS_TRACKMODE_UNKNOWN 0x00
#define MDS_TRACKMODE_AUDIO 0xA9
/* sector size = 2352 */
#define MDS_TRACKMODE_MODE1 0xAA
/* sector size = 2048 */
#define MDS_TRACKMODE_MODE2 0xAB
/* sector size = 2336 */
#define MDS_TRACKMODE_MODE2_FORM1 0xAC
/* sector size = 2048 */
#define MDS_TRACKMODE_MODE2_FORM2 0xAD
/* sector size = 2324 (+4) */
#define MDS_SUBCHAN_NONE 0x00
/* no subchannel */
#define MDS_SUBCHAN_PW_INTERLEAVED 0x08
/* 96-byte PW subchannel, interleaved */
#define MDS_POINT_TRACK_FIRST 0xA0
/* info about first track */
#define MDS_POINT_TRACK_LAST 0xA1
/* info about last track */
#define MDS_POINT_TRACK_LEADOUT 0xA2
/* info about lead-out */
#pragma pack(1)
typedef
struct
{
uae_u8
signature
[
16
];
/* "MEDIA DESCRIPTOR" */
uae_u8
version
[
2
];
/* Version ? */
uae_u16
medium_type
;
/* Medium type */
uae_u16
num_sessions
;
/* Number of sessions */
uae_u16
__dummy1__
[
2
];
/* Wish I knew... */
uae_u16
bca_len
;
/* Length of BCA data (DVD-ROM) */
uae_u32
__dummy2__
[
2
];
uae_u32
bca_data_offset
;
/* Offset to BCA data (DVD-ROM) */
uae_u32
__dummy3__
[
6
];
/* Probably more offsets */
uae_u32
disc_structures_offset
;
/* Offset to disc structures */
uae_u32
__dummy4__
[
3
];
/* Probably more offsets */
uae_u32
sessions_blocks_offset
;
/* Offset to session blocks */
uae_u32
dpm_blocks_offset
;
/* offset to DPM data blocks */
}
MDS_Header
;
/* length: 88 bytes */
typedef
struct
{
uae_s32
session_start
;
/* Session's start address */
uae_s32
session_end
;
/* Session's end address */
uae_u16
session_number
;
/* (Unknown) */
uae_u8
num_all_blocks
;
/* Number of all data blocks. */
uae_u8
num_nontrack_blocks
;
/* Number of lead-in data blocks */
uae_u16
first_track
;
/* Total number of sessions in image? */
uae_u16
last_track
;
/* Number of regular track data blocks. */
uae_u32
__dummy2__
;
/* (unknown) */
uae_u32
tracks_blocks_offset
;
/* Offset of lead-in+regular track data blocks. */
}
MDS_SessionBlock
;
/* length: 24 bytes */
typedef
struct
{
uae_u8
mode
;
/* Track mode */
uae_u8
subchannel
;
/* Subchannel mode */
uae_u8
adr_ctl
;
/* Adr/Ctl */
uae_u8
__dummy2__
;
/* Track flags? */
uae_u8
point
;
/* Track number. (>0x99 is lead-in track) */
uae_u32
__dummy3__
;
uae_u8
min
;
/* Min */
uae_u8
sec
;
/* Sec */
uae_u8
frame
;
/* Frame */
uae_u32
extra_offset
;
/* Start offset of this track's extra block. */
uae_u16
sector_size
;
/* Sector size. */
uae_u8
__dummy4__
[
18
];
uae_u32
start_sector
;
/* Track start sector (PLBA). */
uae_u64
start_offset
;
/* Track start offset. */
uae_u8
session
;
/* Session or index? */
uae_u8
__dummy5__
[
3
];
uae_u32
footer_offset
;
/* Start offset of footer. */
uae_u8
__dummy6__
[
24
];
}
MDS_TrackBlock
;
/* length: 80 bytes */
typedef
struct
{
uae_u32
pregap
;
/* Number of sectors in pregap. */
uae_u32
length
;
/* Number of sectors in track. */
}
MDS_TrackExtraBlock
;
/* length: 8 bytes */
typedef
struct
{
uae_u32
filename_offset
;
/* Start offset of image filename. */
uae_u32
widechar_filename
;
/* Seems to be set to 1 if widechar filename is used */
uae_u32
__dummy1__
;
uae_u32
__dummy2__
;
}
MDS_Footer
;
/* length: 16 bytes */
#pragma pack()
static
int
parsemds
(
struct
cdunit
*
cdu
,
struct
zfile
*
zmds
,
const
TCHAR
*
img
)
{
MDS_Header
*
head
;
struct
cdtoc
*
t
;
uae_u8
*
mds
=
NULL
;
write_log
(
"MDS TOC: '%s'
\n
"
,
img
);
int
size
=
zfile_size
(
zmds
);
mds
=
xmalloc
(
uae_u8
,
size
);
if
(
!
mds
)
goto
end
;
if
(
zfile_fread
(
mds
,
size
,
1
,
zmds
)
!=
1
)
goto
end
;
head
=
(
MDS_Header
*
)
mds
;
if
(
!
memcmp
(
&
head
,
MEDIA_DESCRIPTOR
,
strlen
(
MEDIA_DESCRIPTOR
)))
goto
end
;
if
(
head
->
version
[
0
]
!=
1
)
{
write_log
(
"unsupported MDS version %d, only v.1 supported
\n
"
,
head
->
version
[
0
]);
goto
end
;
}
MDS_SessionBlock
*
sb
=
(
MDS_SessionBlock
*
)(
mds
+
head
->
sessions_blocks_offset
);
cdu
->
tracks
=
sb
->
last_track
-
sb
->
first_track
+
1
;
for
(
int
i
=
0
;
i
<
sb
->
num_all_blocks
;
i
++
)
{
MDS_TrackBlock
*
tb
=
(
MDS_TrackBlock
*
)(
mds
+
sb
->
tracks_blocks_offset
+
i
*
sizeof
MDS_TrackBlock
);
int
point
=
tb
->
point
;
int
tracknum
=
-
1
;
if
(
point
==
0xa2
)
tracknum
=
cdu
->
tracks
;
else
if
(
point
>=
1
&&
point
<=
99
)
tracknum
=
point
-
1
;
if
(
tracknum
>=
0
)
{
MDS_Footer
*
footer
=
tb
->
footer_offset
==
0
?
NULL
:
(
MDS_Footer
*
)(
mds
+
tb
->
footer_offset
);
MDS_TrackExtraBlock
*
teb
=
tb
->
extra_offset
==
0
?
NULL
:
(
MDS_TrackExtraBlock
*
)(
mds
+
tb
->
extra_offset
);
t
=
&
cdu
->
toc
[
tracknum
];
t
->
adr
=
tb
->
adr_ctl
>>
4
;
t
->
ctrl
=
tb
->
adr_ctl
&
15
;
if
(
point
==
0xa2
)
t
->
address
=
sb
->
session_end
;
else
t
->
address
=
tb
->
start_sector
;
t
->
track
=
point
;
t
->
offset
=
tb
->
start_offset
;
t
->
size
=
tb
->
sector_size
;
if
(
footer
)
{
TCHAR
*
fname
=
NULL
;
if
(
footer
->
widechar_filename
==
0
)
fname
=
au
((
char
*
)(
mds
+
footer
->
filename_offset
));
else
fname
=
my_strdup
((
wchar_t
*
)(
mds
+
footer
->
filename_offset
));
if
(
fname
[
0
]
==
'*'
&&
fname
[
1
]
==
'.'
)
{
TCHAR
newname
[
MAX_DPATH
];
_tcscpy
(
newname
,
img
);
TCHAR
*
ext
=
_tcsrchr
(
newname
,
'.'
);
if
(
ext
)
_tcscpy
(
ext
,
fname
+
1
);
xfree
(
fname
);
fname
=
my_strdup
(
newname
);
}
t
->
handle
=
zfile_fopen
(
fname
,
"rb"
,
ZFD_NORMAL
);
t
->
fname
=
my_strdup
(
fname
);
if
(
t
->
handle
)
t
->
filesize
=
zfile_size
(
t
->
handle
);
}
if
(
tb
->
subchannel
&&
t
->
handle
)
{
t
->
suboffset
=
t
->
offset
+
t
->
size
;
t
->
subcode
=
1
;
// interleaved
t
->
subhandle
=
zfile_dup
(
t
->
handle
);
t
->
skipsize
=
SUB_CHANNEL_SIZE
;
t
->
size
-=
SUB_CHANNEL_SIZE
;
if
((
t
->
ctrl
&
0x0c
)
!=
4
)
t
->
enctype
=
AUDENC_PCM
;
}
}
}
end:
xfree
(
mds
);
return
cdu
->
tracks
;
}
static
int
parseccd
(
struct
cdunit
*
cdu
,
struct
zfile
*
zcue
,
const
TCHAR
*
img
)
{
int
mode
;
int
num
,
tracknum
,
trackmode
;
int
adr
,
control
,
lba
;
bool
gotlba
;
struct
cdtoc
*
t
;
struct
zfile
*
zimg
,
*
zsub
;
TCHAR
fname
[
MAX_DPATH
];
write_log
(
"CCD TOC: '%s'
\n
"
,
img
);
_tcscpy
(
fname
,
img
);
TCHAR
*
ext
=
_tcsrchr
(
fname
,
'.'
);
if
(
ext
)
*
ext
=
0
;
_tcscat
(
fname
,
".img"
);
zimg
=
zfile_fopen
(
fname
,
"rb"
,
ZFD_NORMAL
);
if
(
!
zimg
)
{
write_log
(
"CCD: can't open '%s'
\n
"
,
fname
);
//return 0;
}
ext
=
_tcsrchr
(
fname
,
'.'
);
if
(
ext
)
*
ext
=
0
;
_tcscat
(
fname
,
".sub"
);
zsub
=
zfile_fopen
(
fname
,
"rb"
,
ZFD_NORMAL
);
if
(
zsub
)
write_log
(
"CCD: '%s' detected
\n
"
,
fname
);
num
=
-
1
;
mode
=
-
1
;
for
(;;)
{
TCHAR
buf
[
MAX_DPATH
],
*
p
;
if
(
!
zfile_fgets
(
buf
,
sizeof
buf
/
sizeof
(
TCHAR
),
zcue
))
break
;
p
=
buf
;
skipspace
(
&
p
);
if
(
!
_tcsnicmp
(
p
,
"[DISC]"
,
6
))
{
mode
=
1
;
}
else
if
(
!
_tcsnicmp
(
p
,
"[ENTRY "
,
7
))
{
t
=
NULL
;
mode
=
2
;
num
=
readval
(
p
+
7
);
if
(
num
<
0
)
break
;
adr
=
control
=
-
1
;
gotlba
=
false
;
}
else
if
(
!
_tcsnicmp
(
p
,
"[TRACK "
,
7
))
{
mode
=
3
;
tracknum
=
readval
(
p
+
7
);
trackmode
=
-
1
;
if
(
tracknum
<=
0
||
tracknum
>
99
)
break
;
t
=
&
cdu
->
toc
[
tracknum
-
1
];
}
if
(
mode
<
0
)
continue
;
if
(
mode
==
1
)
{
if
(
!
_tcsnicmp
(
p
,
"TocEntries="
,
11
))
{
cdu
->
tracks
=
readval
(
p
+
11
)
-
3
;
if
(
cdu
->
tracks
<=
0
||
cdu
->
tracks
>
99
)
break
;
}
continue
;
}
if
(
cdu
->
tracks
<=
0
)
break
;
if
(
mode
==
2
)
{
if
(
!
_tcsnicmp
(
p
,
"SESSION="
,
8
))
{
if
(
readval
(
p
+
8
)
!=
1
)
mode
=
-
1
;
continue
;
}
else
if
(
!
_tcsnicmp
(
p
,
"POINT="
,
6
))
{
tracknum
=
readval
(
p
+
6
);
if
(
tracknum
<=
0
)
break
;
if
(
tracknum
>=
0xa0
&&
tracknum
!=
0xa2
)
{
mode
=
-
1
;
continue
;
}
if
(
tracknum
==
0xa2
)
tracknum
=
cdu
->
tracks
+
1
;
t
=
&
cdu
->
toc
[
tracknum
-
1
];
continue
;
}
if
(
!
_tcsnicmp
(
p
,
"ADR="
,
4
))
adr
=
readval
(
p
+
4
);
if
(
!
_tcsnicmp
(
p
,
"CONTROL="
,
8
))
control
=
readval
(
p
+
8
);
if
(
!
_tcsnicmp
(
p
,
"PLBA="
,
5
))
{
lba
=
readval
(
p
+
5
);
gotlba
=
true
;
}
if
(
gotlba
&&
adr
>=
0
&&
control
>=
0
)
{
t
->
adr
=
adr
;
t
->
ctrl
=
control
;
t
->
address
=
lba
;
t
->
offset
=
0
;
t
->
size
=
2352
;
t
->
offset
=
lba
*
t
->
size
;
t
->
track
=
tracknum
;
if
((
control
&
0x0c
)
!=
4
)
t
->
enctype
=
AUDENC_PCM
;
if
(
zsub
)
{
t
->
subcode
=
2
;
t
->
subhandle
=
zfile_dup
(
zsub
);
t
->
suboffset
=
0
;
}
if
(
zimg
)
{
t
->
handle
=
zfile_dup
(
zimg
);
t
->
fname
=
my_strdup
(
zfile_getname
(
zimg
));
}
mode
=
-
1
;
}
}
else
if
(
mode
==
3
)
{
if
(
!
_tcsnicmp
(
p
,
"MODE="
,
5
))
trackmode
=
_tstol
(
p
+
5
);
if
(
trackmode
<
0
||
trackmode
>
2
)
continue
;
}
}
return
cdu
->
tracks
;
}
static
int
parsecue
(
struct
cdunit
*
cdu
,
struct
zfile
*
zcue
,
const
TCHAR
*
img
)
{
int
tracknum
,
index0
,
pregap
;
int
offset
,
secoffset
,
newfile
;
TCHAR
*
fname
,
*
fnametype
;
audenc
fnametypeid
;
int
ctrl
;
mp3decoder
*
mp3dec
=
NULL
;
fname
=
NULL
;
fnametype
=
NULL
;
tracknum
=
0
;
offset
=
0
;
secoffset
=
0
;
newfile
=
0
;
ctrl
=
0
;
index0
=
-
1
;
pregap
=
0
;
fnametypeid
=
AUDENC_NONE
;
write_log
(
"CUE TOC: '%s'
\n
"
,
img
);
for
(;;)
{
TCHAR
buf
[
MAX_DPATH
],
*
p
;
if
(
!
zfile_fgets
(
buf
,
sizeof
buf
/
sizeof
(
TCHAR
),
zcue
))
break
;
p
=
buf
;
skipspace
(
&
p
);
if
(
!
_tcsnicmp
(
p
,
"FILE"
,
4
))
{
p
+=
4
;
xfree
(
fname
);
fname
=
my_strdup
(
nextstring
(
&
p
));
fnametype
=
nextstring
(
&
p
);
fnametypeid
=
AUDENC_NONE
;
if
(
!
fnametype
)
break
;
if
(
_tcsicmp
(
fnametype
,
"BINARY"
)
&&
_tcsicmp
(
fnametype
,
"WAVE"
)
&&
_tcsicmp
(
fnametype
,
"MP3"
))
{
write_log
(
"CUE: unknown file type '%s' ('%s')
\n
"
,
fnametype
,
fname
);
}
fnametypeid
=
AUDENC_PCM
;
if
(
!
_tcsicmp
(
fnametype
,
"MP3"
))
fnametypeid
=
AUDENC_MP3
;
else
if
(
!
_tcsicmp
(
fnametype
,
"FLAC"
))
fnametypeid
=
AUDENC_FLAC
;
offset
=
0
;
newfile
=
1
;
ctrl
=
0
;
}
else
if
(
!
_tcsnicmp
(
p
,
"FLAGS"
,
5
))
{
ctrl
&=
~
(
1
|
2
|
8
);
for
(;;)
{
TCHAR
*
f
=
nextstring
(
&
p
);
if
(
!
f
)
break
;
if
(
!
_tcsicmp
(
f
,
"PRE"
))
ctrl
|=
1
;
if
(
!
_tcsicmp
(
f
,
"DCP"
))
ctrl
|=
2
;
if
(
!
_tcsicmp
(
f
,
"4CH"
))
ctrl
|=
8
;
}
}
else
if
(
!
_tcsnicmp
(
p
,
"TRACK"
,
5
))
{
int
size
;
TCHAR
*
tracktype
;
p
+=
5
;
//pregap = 0;
index0
=
-
1
;
tracknum
=
_tstoi
(
nextstring
(
&
p
));
tracktype
=
nextstring
(
&
p
);
if
(
!
tracktype
)
break
;
size
=
2352
;
if
(
!
_tcsicmp
(
tracktype
,
"AUDIO"
))
{
ctrl
&=
~
4
;
}
else
{
ctrl
|=
4
;
if
(
!
_tcsicmp
(
tracktype
,
"MODE1/2048"
))
size
=
2048
;
else
if
(
!
_tcsicmp
(
tracktype
,
"MODE1/2352"
))
size
=
2352
;
else
if
(
!
_tcsicmp
(
tracktype
,
"MODE2/2336"
)
||
!
_tcsicmp
(
tracktype
,
"CDI/2336"
))
size
=
2336
;
else
if
(
!
_tcsicmp
(
tracktype
,
"MODE2/2352"
)
||
!
_tcsicmp
(
tracktype
,
"CDI/2352"
))
size
=
2352
;
else
{
write_log
(
"CUE: unknown tracktype '%s' ('%s')
\n
"
,
tracktype
,
fname
);
}
}
if
(
tracknum
>=
1
&&
tracknum
<=
99
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
tracknum
-
1
];
struct
zfile
*
ztrack
;
if
(
tracknum
>
1
&&
newfile
)
{
t
--
;
secoffset
+=
t
->
filesize
/
t
->
size
;
t
++
;
}
newfile
=
0
;
ztrack
=
zfile_fopen
(
fname
,
"rb"
,
ZFD_ARCHIVE
|
ZFD_DELAYEDOPEN
);
if
(
!
ztrack
)
{
TCHAR
tmp
[
MAX_DPATH
];
_tcscpy
(
tmp
,
fname
);
p
=
tmp
+
_tcslen
(
tmp
);
while
(
p
>
tmp
)
{
if
(
*
p
==
'/'
||
*
p
==
'\\'
)
{
ztrack
=
zfile_fopen
(
p
+
1
,
"rb"
,
ZFD_ARCHIVE
|
ZFD_DELAYEDOPEN
);
if
(
ztrack
)
{
xfree
(
fname
);
fname
=
my_strdup
(
p
+
1
);
}
break
;
}
p
--
;
}
}
if
(
!
ztrack
)
{
TCHAR
tmp
[
MAX_DPATH
];
TCHAR
*
s2
;
_tcscpy
(
tmp
,
zfile_getname
(
zcue
));
s2
=
_tcsrchr
(
tmp
,
'\\'
);
if
(
!
s2
)
s2
=
_tcsrchr
(
tmp
,
'/'
);
if
(
s2
)
{
s2
[
0
]
=
0
;
_tcscat
(
tmp
,
"
\\
"
);
_tcscat
(
tmp
,
fname
);
ztrack
=
zfile_fopen
(
tmp
,
"rb"
,
ZFD_ARCHIVE
|
ZFD_DELAYEDOPEN
);
}
}
t
->
track
=
tracknum
;
t
->
ctrl
=
ctrl
;
t
->
adr
=
1
;
t
->
handle
=
ztrack
;
t
->
size
=
size
;
t
->
fname
=
my_strdup
(
fname
);
if
(
tracknum
>
cdu
->
tracks
)
cdu
->
tracks
=
tracknum
;
if
(
t
->
handle
)
t
->
filesize
=
zfile_size
(
t
->
handle
);
}
}
else
if
(
!
_tcsnicmp
(
p
,
"PREGAP"
,
6
))
{
TCHAR
*
tt
;
int
tn
;
p
+=
6
;
tt
=
nextstring
(
&
p
);
tn
=
_tstoi
(
tt
)
*
60
*
75
;
tn
+=
_tstoi
(
tt
+
3
)
*
75
;
tn
+=
_tstoi
(
tt
+
6
);
pregap
+=
tn
;
}
else
if
(
!
_tcsnicmp
(
p
,
"INDEX"
,
5
))
{
int
idxnum
;
int
tn
=
0
;
TCHAR
*
tt
;
p
+=
5
;
idxnum
=
_tstoi
(
nextstring
(
&
p
));
tt
=
nextstring
(
&
p
);
tn
=
_tstoi
(
tt
)
*
60
*
75
;
tn
+=
_tstoi
(
tt
+
3
)
*
75
;
tn
+=
_tstoi
(
tt
+
6
);
if
(
idxnum
==
0
)
{
index0
=
tn
;
}
else
if
(
idxnum
==
1
&&
tracknum
>=
1
&&
tracknum
<=
99
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
tracknum
-
1
];
if
(
!
t
->
address
)
{
t
->
address
=
tn
+
secoffset
;
t
->
address
+=
pregap
;
if
(
tracknum
>
1
)
{
offset
+=
t
->
address
-
t
[
-
1
].
address
;
}
else
{
offset
+=
t
->
address
;
}
if
(
!
secoffset
)
t
->
offset
=
offset
*
t
->
size
;
if
(
fnametypeid
==
AUDENC_PCM
&&
t
->
handle
)
{
struct
zfile
*
zf
=
t
->
handle
;
uae_u8
buf
[
16
]
=
{
0
};
zfile_fread
(
buf
,
12
,
1
,
zf
);
if
(
!
memcmp
(
buf
,
"RIFF"
,
4
)
&&
!
memcmp
(
buf
+
8
,
"WAVE"
,
4
))
{
int
size
;
for
(;;)
{
memset
(
buf
,
0
,
sizeof
buf
);
if
(
zfile_fread
(
buf
,
8
,
1
,
zf
)
!=
1
)
break
;
size
=
(
buf
[
4
]
<<
0
)
|
(
buf
[
5
]
<<
8
)
|
(
buf
[
6
]
<<
16
)
|
(
buf
[
7
]
<<
24
);
if
(
!
memcmp
(
buf
,
"data"
,
4
))
break
;
if
(
size
<=
0
)
break
;
zfile_fseek
(
zf
,
size
,
SEEK_CUR
);
}
t
->
offset
+=
zfile_ftell
(
zf
);
t
->
filesize
=
size
;
}
t
->
enctype
=
fnametypeid
;
}
else
if
(
fnametypeid
==
AUDENC_MP3
&&
t
->
handle
)
{
if
(
!
mp3dec
)
{
try
{
mp3dec
=
new
mp3decoder
();
}
catch
(
exception
)
{
}
}
if
(
mp3dec
)
{
t
->
offset
=
0
;
t
->
filesize
=
mp3dec
->
getsize
(
t
->
handle
);
if
(
t
->
filesize
)
t
->
enctype
=
fnametypeid
;
}
}
else
if
(
fnametypeid
==
AUDENC_FLAC
&&
t
->
handle
)
{
flac_get_size
(
t
);
if
(
t
->
filesize
)
t
->
enctype
=
fnametypeid
;
}
}
}
}
}
struct
cdtoc
*
t
=
&
cdu
->
toc
[
cdu
->
tracks
-
1
];
int
size
=
t
->
filesize
;
if
(
!
secoffset
)
size
-=
offset
*
t
->
size
;
if
(
size
<
0
)
size
=
0
;
cdu
->
toc
[
cdu
->
tracks
].
address
=
t
->
address
+
size
/
t
->
size
;
xfree
(
fname
);
delete
mp3dec
;
return
cdu
->
tracks
;
}
static
int
parse_image
(
struct
cdunit
*
cdu
,
const
TCHAR
*
img
)
{
struct
zfile
*
zcue
;
int
i
;
const
TCHAR
*
ext
;
int
secoffset
;
secoffset
=
0
;
cdu
->
tracks
=
0
;
if
(
!
img
)
return
0
;
zcue
=
zfile_fopen
(
img
,
"rb"
,
ZFD_ARCHIVE
|
ZFD_CD
|
ZFD_DELAYEDOPEN
);
if
(
!
zcue
)
return
0
;
ext
=
_tcsrchr
(
zfile_getname
(
zcue
),
'.'
);
if
(
ext
)
{
TCHAR
curdir
[
MAX_DPATH
];
TCHAR
oldcurdir
[
MAX_DPATH
],
*
p
;
ext
++
;
oldcurdir
[
0
]
=
0
;
_tcscpy
(
curdir
,
img
);
p
=
curdir
+
_tcslen
(
curdir
);
while
(
p
>
curdir
)
{
if
(
*
p
==
'/'
||
*
p
==
'\\'
)
break
;
p
--
;
}
*
p
=
0
;
if
(
p
>
curdir
)
my_setcurrentdir
(
curdir
,
oldcurdir
);
if
(
!
_tcsicmp
(
ext
,
"cue"
))
parsecue
(
cdu
,
zcue
,
img
);
else
if
(
!
_tcsicmp
(
ext
,
"ccd"
))
parseccd
(
cdu
,
zcue
,
img
);
else
if
(
!
_tcsicmp
(
ext
,
"mds"
))
parsemds
(
cdu
,
zcue
,
img
);
if
(
oldcurdir
[
0
])
my_setcurrentdir
(
oldcurdir
,
NULL
);
}
if
(
!
cdu
->
tracks
)
{
uae_u64
siz
=
zfile_size
(
zcue
);
if
(
siz
>=
16384
&&
(
siz
%
2048
)
==
0
||
(
siz
%
2352
)
==
0
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
0
];
cdu
->
tracks
=
1
;
t
->
ctrl
=
4
;
t
->
adr
=
1
;
t
->
fname
=
my_strdup
(
img
);
t
->
handle
=
zcue
;
t
->
size
=
(
siz
%
2048
)
==
0
?
2048
:
2352
;
t
->
filesize
=
siz
;
write_log
(
"CUE: plain CD image mounted!
\n
"
);
cdu
->
toc
[
1
].
address
=
t
->
address
+
t
->
filesize
/
t
->
size
;
zcue
=
NULL
;
}
}
for
(
i
=
0
;
i
<=
cdu
->
tracks
;
i
++
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
i
];
uae_u32
msf
=
lsn2msf
(
t
->
address
);
if
(
i
<
cdu
->
tracks
)
write_log
(
"%2d: "
,
i
+
1
);
else
write_log
(
" "
);
write_log
(
"%7d %02d:%02d:%02d"
,
t
->
address
,
(
msf
>>
16
)
&
0xff
,
(
msf
>>
8
)
&
0xff
,
(
msf
>>
0
)
&
0xff
);
if
(
i
<
cdu
->
tracks
)
write_log
(
" %s %x %10d %10d %s"
,
(
t
->
ctrl
&
4
)
?
"DATA "
:
(
t
->
subcode
?
"CDA+SUB"
:
"CDA "
),
t
->
ctrl
,
t
->
offset
,
t
->
filesize
,
t
->
handle
==
NULL
?
"[FILE ERROR]"
:
""
);
write_log
(
"
\n
"
);
if
(
i
<
cdu
->
tracks
)
write_log
(
" - %s
\n
"
,
t
->
fname
);
if
(
t
->
handle
&&
!
t
->
filesize
)
t
->
filesize
=
zfile_size
(
t
->
handle
);
}
cdu
->
blocksize
=
2048
;
cdu
->
cdsize
=
cdu
->
toc
[
cdu
->
tracks
].
address
*
cdu
->
blocksize
;
zfile_fclose
(
zcue
);
return
1
;
}
static
int
ismedia
(
int
unitnum
,
int
quick
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
unitnum
];
if
(
!
cdu
->
enabled
)
return
-
1
;
return
cdu
->
tracks
>
0
?
1
:
0
;
}
static
struct
device_info
*
info_device
(
int
unitnum
,
struct
device_info
*
di
,
int
quick
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
unitnum
];
memset
(
di
,
0
,
sizeof
(
struct
device_info
));
if
(
!
cdu
->
enabled
)
return
0
;
di
->
open
=
cdu
->
open
;
di
->
slow_unit
=
cdu
->
slowunit
;
di
->
removable
=
1
;
di
->
bus
=
unitnum
;
di
->
target
=
0
;
di
->
lun
=
0
;
di
->
media_inserted
=
0
;
di
->
bytespersector
=
2048
;
di
->
mediapath
[
0
]
=
0
;
di
->
cylinders
=
1
;
di
->
trackspercylinder
=
1
;
di
->
sectorspertrack
=
cdu
->
cdsize
/
di
->
bytespersector
;
if
(
ismedia
(
unitnum
,
1
))
{
di
->
media_inserted
=
1
;
_tcscpy
(
di
->
mediapath
,
currprefs
.
cdslots
[
unitnum
].
name
);
}
memset
(
&
di
->
toc
,
0
,
sizeof
(
struct
cd_toc_head
));
command_toc
(
unitnum
,
&
di
->
toc
);
di
->
write_protected
=
1
;
di
->
type
=
INQ_ROMD
;
di
->
unitnum
=
unitnum
+
1
;
if
(
di
->
mediapath
[
0
])
{
_tcscpy
(
di
->
label
,
"IMG:"
);
_tcscat
(
di
->
label
,
di
->
mediapath
);
}
else
{
_tcscpy
(
di
->
label
,
"IMG:<EMPTY>"
);
}
di
->
backend
=
"IMAGE"
;
return
di
;
}
static
void
unload_image
(
struct
cdunit
*
cdu
)
{
int
i
;
for
(
i
=
0
;
i
<
cdu
->
tracks
;
i
++
)
{
struct
cdtoc
*
t
=
&
cdu
->
toc
[
i
];
zfile_fclose
(
t
->
handle
);
if
(
t
->
handle
!=
t
->
subhandle
)
zfile_fclose
(
t
->
subhandle
);
xfree
(
t
->
fname
);
xfree
(
t
->
data
);
xfree
(
t
->
subdata
);
}
memset
(
cdu
->
toc
,
0
,
sizeof
cdu
->
toc
);
cdu
->
tracks
=
0
;
cdu
->
cdsize
=
0
;
}
static
int
open_device
(
int
unitnum
,
const
TCHAR
*
ident
,
int
flags
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
unitnum
];
if
(
cdu
->
open
)
return
0
;
uae_sem_init
(
&
cdu
->
sub_sem
,
0
,
1
);
parse_image
(
cdu
,
ident
);
cdu
->
open
=
true
;
cdu
->
enabled
=
true
;
cdu
->
cdda_volume
[
0
]
=
0x7fff
;
cdu
->
cdda_volume
[
1
]
=
0x7fff
;
cdu
->
slowunit
=
(
flags
&
1
)
!=
0
;
blkdev_cd_change
(
unitnum
,
currprefs
.
cdslots
[
unitnum
].
name
);
if
(
cdimage_unpack_thread
==
0
)
{
init_comm_pipe
(
&
unpack_pipe
,
10
,
1
);
uae_start_thread
(
"cdimage_unpack"
,
cdda_unpack_func
,
NULL
,
NULL
);
while
(
cdimage_unpack_thread
==
0
)
Sleep
(
10
);
}
return
1
;
}
static
void
close_device
(
int
unitnum
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
unitnum
];
if
(
cdu
->
open
==
false
)
return
;
cdda_stop
(
cdu
);
unload_image
(
cdu
);
uae_sem_destroy
(
&
cdu
->
sub_sem
);
cdu
->
open
=
false
;
blkdev_cd_change
(
unitnum
,
currprefs
.
cdslots
[
unitnum
].
name
);
if
(
cdimage_unpack_thread
)
{
cdimage_unpack_thread
=
0
;
write_comm_pipe_u32
(
&
unpack_pipe
,
-
1
,
0
);
write_comm_pipe_u32
(
&
unpack_pipe
,
-
1
,
1
);
while
(
cdimage_unpack_thread
==
0
)
Sleep
(
10
);
cdimage_unpack_thread
=
0
;
destroy_comm_pipe
(
&
unpack_pipe
);
}
}
static
void
close_bus
(
void
)
{
if
(
!
bus_open
)
{
write_log
(
"IMAGE close_bus() when already closed!
\n
"
);
return
;
}
for
(
int
i
=
0
;
i
<
MAX_TOTAL_SCSI_DEVICES
;
i
++
)
{
struct
cdunit
*
cdu
=
&
cdunits
[
i
];
if
(
cdu
->
open
)
close_device
(
i
);
cdu
->
enabled
=
false
;
}
bus_open
=
0
;
write_log
(
"IMAGE driver closed.
\n
"
);
}
static
int
open_bus
(
int
flags
)
{
if
(
bus_open
)
{
write_log
(
"IOCTL open_bus() more than once!
\n
"
);
return
1
;
}
bus_open
=
1
;
write_log
(
"Image driver open.
\n
"
);
return
1
;
}
struct
device_functions
devicefunc_cdimage
=
{
L"IMAGE"
,
open_bus
,
close_bus
,
open_device
,
close_device
,
info_device
,
0
,
0
,
0
,
command_pause
,
command_stop
,
command_play
,
command_volume
,
command_qcode
,
command_toc
,
command_read
,
command_rawread
,
0
,
0
,
ismedia
};
src/inprec.c
0 → 100755
View file @
c130c99e
static
uae_u8
*
inprec_buffer
,
*
inprec_p
;
static
struct
zfile
*
inprec_zf
;
static
int
inprec_size
;
int
input_recording
=
0
;
static
uae_u8
*
inprec_plast
,
*
inprec_plastptr
;
static
int
inprec_div
;
static
uae_u32
oldbuttons
[
4
];
static
uae_u16
oldjoy
[
2
];
int
inprec_open
(
char
*
fname
,
int
record
)
{
uae_u32
t
=
(
uae_u32
)
time
(
0
);
int
i
;
inprec_close
();
inprec_zf
=
zfile_fopen
(
fname
,
record
>
0
?
"wb"
:
"rb"
);
if
(
inprec_zf
==
NULL
)
return
0
;
inprec_size
=
10000
;
inprec_div
=
1
;
if
(
record
<
0
)
{
uae_u32
id
;
zfile_fseek
(
inprec_zf
,
0
,
SEEK_END
);
inprec_size
=
zfile_ftell
(
inprec_zf
);
zfile_fseek
(
inprec_zf
,
0
,
SEEK_SET
);
inprec_buffer
=
inprec_p
=
(
uae_u8
*
)
xmalloc
(
inprec_size
);
zfile_fread
(
inprec_buffer
,
inprec_size
,
1
,
inprec_zf
);
inprec_plastptr
=
inprec_buffer
;
id
=
inprec_pu32
();
if
(
id
!=
'
UAE
\
0
'
)
{
inprec_close
();
return
0
;
}
inprec_pu32
();
t
=
inprec_pu32
();
i
=
inprec_pu32
();
while
(
i
--
>
0
)
inprec_pu8
();
inprec_p
=
inprec_plastptr
;
oldbuttons
[
0
]
=
oldbuttons
[
1
]
=
oldbuttons
[
2
]
=
oldbuttons
[
3
]
=
0
;
oldjoy
[
0
]
=
oldjoy
[
1
]
=
0
;
if
(
record
<
-
1
)
inprec_div
=
maxvpos
;
}
else
if
(
record
>
0
)
{
inprec_buffer
=
inprec_p
=
(
uae_u8
*
)
xmalloc
(
inprec_size
);
inprec_ru32
(
'
UAE
\
0
'
);
inprec_ru8
(
1
);
inprec_ru8
(
UAEMAJOR
);
inprec_ru8
(
UAEMINOR
);
inprec_ru8
(
UAESUBREV
);
inprec_ru32
(
t
);
inprec_ru32
(
0
);
// extra header size
}
else
{
return
0
;
}
input_recording
=
record
;
srand
(
t
);
CIA_inprec_prepare
();
write_log
(
"inprec initialized '%s', mode=%d
\n
"
,
fname
,
input_recording
);
return
1
;
}
void
inprec_close
(
void
)
{
if
(
!
inprec_zf
)
return
;
if
(
inprec_buffer
&&
input_recording
>
0
)
{
hsync_counter
++
;
inprec_rstart
(
INPREC_END
);
inprec_rend
();
hsync_counter
--
;
zfile_fwrite
(
inprec_buffer
,
inprec_p
-
inprec_buffer
,
1
,
inprec_zf
);
inprec_p
=
inprec_buffer
;
}
zfile_fclose
(
inprec_zf
);
inprec_zf
=
NULL
;
xfree
(
inprec_buffer
);
inprec_buffer
=
NULL
;
input_recording
=
0
;
write_log
(
"inprec finished
\n
"
);
}
void
inprec_ru8
(
uae_u8
v
)
{
*
inprec_p
++=
v
;
}
void
inprec_ru16
(
uae_u16
v
)
{
inprec_ru8
((
uae_u8
)(
v
>>
8
));
inprec_ru8
((
uae_u8
)
v
);
}
void
inprec_ru32
(
uae_u32
v
)
{
inprec_ru16
((
uae_u16
)(
v
>>
16
));
inprec_ru16
((
uae_u16
)
v
);
}
void
inprec_rstr
(
const
char
*
s
)
{
while
(
*
s
)
{
inprec_ru8
(
*
s
);
s
++
;
}
inprec_ru8
(
0
);
}
void
inprec_rstart
(
uae_u8
type
)
{
write_log
(
"INPREC: %08X: %d
\n
"
,
hsync_counter
,
type
);
inprec_ru32
(
hsync_counter
);
inprec_ru8
(
0
);
inprec_plast
=
inprec_p
;
inprec_ru8
(
0xff
);
inprec_ru8
(
type
);
}
void
inprec_rend
(
void
)
{
*
inprec_plast
=
inprec_p
-
(
inprec_plast
+
2
);
if
(
inprec_p
>=
inprec_buffer
+
inprec_size
-
256
)
{
zfile_fwrite
(
inprec_buffer
,
inprec_p
-
inprec_buffer
,
1
,
inprec_zf
);
inprec_p
=
inprec_buffer
;
}
}
int
inprec_pstart
(
uae_u8
type
)
{
uae_u8
*
p
=
inprec_p
;
uae_u32
hc
=
hsync_counter
;
static
uae_u8
*
lastp
;
uae_u32
hc_orig
,
hc2_orig
;
if
(
savestate_state
)
return
0
;
if
(
p
[
5
+
1
]
==
INPREC_END
)
{
inprec_close
();
return
0
;
}
hc_orig
=
hc
;
hc
/=
inprec_div
;
hc
*=
inprec_div
;
for
(;;)
{
uae_u32
hc2
=
(
p
[
0
]
<<
24
)
|
(
p
[
1
]
<<
16
)
|
(
p
[
2
]
<<
8
)
|
p
[
3
];
if
(
p
>
lastp
)
{
write_log
(
"INPREC: Next %08x (%08x=%d): %d (%d)
\n
"
,
hc2
,
hc
,
hc2
-
hc
,
p
[
5
+
1
],
p
[
5
]);
lastp
=
p
;
}
hc2_orig
=
hc2
;
hc2
/=
inprec_div
;
hc2
*=
inprec_div
;
if
(
hc
>
hc2
)
{
write_log
(
"INPREC: %08x > %08x: %d (%d) missed!
\n
"
,
hc
,
hc2
,
p
[
5
+
1
],
p
[
5
]);
inprec_close
();
return
0
;
}
if
(
hc2
!=
hc
)
{
lastp
=
p
;
break
;
}
if
(
p
[
5
+
1
]
==
type
)
{
write_log
(
"INPREC: %08x: %d (%d) (%+d)
\n
"
,
hc
,
type
,
p
[
5
],
hc_orig
-
hc2_orig
);
inprec_plast
=
p
;
inprec_plastptr
=
p
+
5
+
2
;
return
1
;
}
p
+=
5
+
2
+
p
[
5
];
}
inprec_plast
=
NULL
;
return
0
;
}
void
inprec_pend
(
void
)
{
uae_u8
*
p
=
inprec_p
;
uae_u32
hc
=
hsync_counter
;
if
(
!
inprec_plast
)
return
;
inprec_plast
[
5
+
1
]
=
0
;
inprec_plast
=
NULL
;
inprec_plastptr
=
NULL
;
hc
/=
inprec_div
;
hc
*=
inprec_div
;
for
(;;)
{
uae_u32
hc2
=
(
p
[
0
]
<<
24
)
|
(
p
[
1
]
<<
16
)
|
(
p
[
2
]
<<
8
)
|
p
[
3
];
hc2
/=
inprec_div
;
hc2
*=
inprec_div
;
if
(
hc2
!=
hc
)
break
;
if
(
p
[
5
+
1
]
!=
0
)
return
;
p
+=
5
+
2
+
p
[
5
];
}
inprec_p
=
p
;
if
(
p
[
5
+
1
]
==
INPREC_END
)
inprec_close
();
}
uae_u8
inprec_pu8
(
void
)
{
return
*
inprec_plastptr
++
;
}
uae_u16
inprec_pu16
(
void
)
{
uae_u16
v
=
inprec_pu8
()
<<
8
;
v
|=
inprec_pu8
();
return
v
;
}
uae_u32
inprec_pu32
(
void
)
{
uae_u32
v
=
inprec_pu16
()
<<
16
;
v
|=
inprec_pu16
();
return
v
;
}
int
inprec_pstr
(
char
*
s
)
{
int
len
=
0
;
for
(;;)
{
uae_u8
v
=
inprec_pu8
();
*
s
++
=
v
;
if
(
!
v
)
break
;
len
++
;
}
return
len
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment