Initial commit: akai-fetch - AKAI sampler ISO downloader & extractor

- fetch: Go CLI tool for searching, downloading, and extracting
  AKAI sampler ISOs from archive.org
- scripts/extract_wavs.sh: Shell script driving akaiutil to
  convert samples to WAV
- Dockerfile: Multi-stage build packaging akaiutil + fetch
- third_party/akaiutil: Vendored akaiutil v4.6.7 source (GPLv2)
- docs/akaiutil.md: Full akaiutil reference
This commit is contained in:
2026-06-15 22:33:53 -07:00
commit 9f107b5f80
29 changed files with 24620 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# Binaries
fetch
akai-fetch
akai-fetch-bin
*.exe
# Original akaiutil source (vendored copy in third_party/)
akaiutil-4.6.7/
# Build artifacts
*.o
*.obj
# Data
*.iso
output/
wavs
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
# Temp
/tmp/
+33
View File
@@ -0,0 +1,33 @@
# Stage 1: Build akaiutil from source
FROM debian:11 AS akaiutil-builder
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
COPY third_party/akaiutil/ /src/akaiutil/
WORKDIR /src/akaiutil
RUN make
# Stage 2: Build fetch (Go tool)
FROM golang:1.26-alpine AS fetch-builder
WORKDIR /src
COPY go.mod main.go /src/
RUN CGO_ENABLED=0 go build -o /fetch .
# Stage 3: Runtime image
FROM debian:11-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
bash \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=akaiutil-builder /src/akaiutil/akaiutil /usr/local/bin/
COPY --from=fetch-builder /fetch /usr/local/bin/fetch
COPY scripts/extract_wavs.sh /usr/local/bin/
WORKDIR /data
ENTRYPOINT ["fetch"]
CMD ["--help"]
+21
View File
@@ -0,0 +1,21 @@
BIN := fetch
IMAGE := akai-fetch
REMOTE := dhg.lol
build:
CGO_ENABLED=0 go build -o $(BIN) .
docker:
docker build -t $(IMAGE) .
docker-run:
docker run --rm -v "$(PWD)/output:/data" $(IMAGE) $(ARGS)
install: build
scp $(BIN) $(REMOTE):/tmp/$(BIN) && \
ssh $(REMOTE) "sudo mv /tmp/$(BIN) /DATA/Downloads/akai/$(BIN) && sudo chmod +x /DATA/Downloads/akai/$(BIN)"
clean:
rm -f $(BIN)
.PHONY: build docker docker-run install clean
+219
View File
@@ -0,0 +1,219 @@
# akaiutil — AKAI Sampler Filesystem Tool
**Version 4.6.7** (21-OCT-2022) — GPLv2 — by Klaus Michael Indlekofer
Interactive console-based file manager for AKAI **S900/S950/S1000/S1100/S3000/CD3000** sampler disk images, floppies, hard drives, and CD-ROMs.
## Usage
```
akaiutil [-h] [-r] [-F] [-C] [-l <lock-file>] [-o <start-offset>] [-s <pseudo-disk-size>]
[-n <pseudo-disk-number>] [-c <cdrom-index> ...] [-p <physdrive-index> ...]
[[-f] <floppy-drive>] ... [[-f] <disk-file>] ...
```
### Options
| Flag | Description |
|------|-------------|
| `-h` | Print help |
| `-r` | Read-only mode (must come first) |
| `-F` | Disable floppy filesystem detection |
| `-C` | Disable block cache |
| `-l <file>` | Lock file for exclusive access |
| `-o <offset>` | Byte offset where disk data starts (decimal or `0x` hex) |
| `-s <size>` | Pseudo-disk size in KB (for multi-disk images) |
| `-n <num>` | Max pseudo-disks per file descriptor (max 8) |
| `-c <n>` | (Windows) Open CD-ROM `\\.\cdromN` |
| `-p <n>` | (Windows) Open physical drive `\\.\physicaldriveN` |
On Linux, pass raw devices like `/dev/da1`, `/dev/disk2s0`.
### Examples
```bash
# Open a floppy image
akaiutil fff.img
# Open harddisk images
akaiutil hhh1.img hhh2.img
# Multi-harddisk image with explicit size
akaiutil -s 524280 mmm.img
# Linux raw device access
akaiutil /dev/da1 hhh.img
# Read-only CD-ROM (macOS)
akaiutil -r /dev/disk2s0
```
## Virtual Filesystem
```
/disk<N>/<partition-letter>/<volume-name>/<file-name>
```
Shorthand: `/N` = `/diskN`, `/floppyN` = `/diskN/A/<volume1>`. Use `_` for spaces in names. `.` and `..` work as usual.
## Interactive Commands
### Navigation & Info
| Command | Alias | Description |
|---------|-------|-------------|
| `help [<cmd>]` | `man` | List commands or show help for a command |
| `exit` / `quit` | `bye`, `q` | Exit |
| `restart` | — | Rescan disks |
| `restartkeep` | `restart.`, `sync` | Rescan, keep current directory |
| `df` | — | Show disk info (all disks + partitions) |
| `dinfo` | `pwd` | Show current directory info |
| `cd [<path>]` | — | Change directory |
| `cdi <index>` | — | Change to volume by index |
| `dir [<path>]` | `ls` | List directory |
| `dirrec` | `lsrec` | Recursive listing |
| `lcd <path>` | — | Change local (host) directory |
| `ldir` | `lls` | List local directory |
| `dircache` | `lscache` | Show block cache info |
### File Operations
| Command | Alias | Description |
|---------|-------|-------------|
| `del <path>` / `deli <idx>` | `rm` / `rmi` | Delete file |
| `ren <old> <new> [<idx>]` | `mv` | Rename/move file |
| `reni <old-idx> <new> [<idx>]` | `mvi` | Rename by index |
| `copy <src> <dst> [<idx>]` | `cp` | Copy file |
| `copyi <src-idx> <dst> [<idx>]` | `cpi` | Copy by index |
| `infoi <idx>` | — | Show file info |
| `infoall` | — | Show info for all files |
### Import / Export
| Command | Alias | Description |
|---------|-------|-------------|
| `get <path> [<begin> [<end>]]` | `export` | Export file to host |
| `geti <idx> [<begin> [<end>]]` | `exporti` | Export by index |
| `getall` | `exportall` | Export all files |
| `put [<vol>/]<name> [<idx>]` | `import` | Import file (use `*` for all) |
| `getdisk <file>` | `dget`, `dexport` | Export entire disk image |
| `putdisk <file>` | `dput`, `dimport` | Import disk image |
| `getpart [<path>] <file>` | `pget`, `pexport` | Export partition |
| `putpart <file> [<path>]` | `pput`, `pimport` | Import partition |
| `gettags <file>` | `tagsget` | Export partition tags |
| `puttags <file>` | `tagsput` | Import partition tags |
### WAV Conversion
| Command | Alias | Description |
|---------|-------|-------------|
| `sample2wav <path>` / `sample2wavi <idx>` | `s2wav` / `getwav` | Sample → WAV |
| `sample2wavall` | `s2wavall` | All samples → WAV |
| `wav2sample <file> [<idx>]` | `wav2s`, `putwav` | WAV → sample (auto-detect) |
| `wav2sample9` / `wav2sample9c` | `putwav9` / `putwav9c` | WAV → S900 (non-compressed / compressed) |
| `wav2sample1` | `putwav1` | WAV → S1000 |
| `wav2sample3` | `putwav3` | WAV → S3000 |
WAV input must be mono/stereo, 8/16/24/32-bit PCM.
### S900 Compression
| Command | Alias | Description |
|---------|-------|-------------|
| `sample900compr <path>` | `s9compr` | Compress S900 sample |
| `sample900comprall` | `s9comprall` | Compress all S900 samples |
| `sample900uncompr <path>` | `s9uncompr` | Uncompress S900 sample |
| `sample900uncomprall` | `s9uncomprall` | Uncompress all |
### Volume Management
| Command | Alias | Description |
|---------|-------|-------------|
| `mkvol [<path>]` | `mkdir` | Create volume (auto-detect type) |
| `mkvol9` / `mkvol1` / `mkvol3` / `mkvol3cd` | `mkdir9` etc. | Create S900/S1000/S3000/CD3000 volume |
| `mkvoli <idx> [<name> [<load-num>]]` | `mkdiri` | Create volume at specific index |
| `delvol <path>` / `delvoli <idx>` | `rmdir` | Delete volume |
| `wipevol <path>` / `wipevoli <idx>` | `rmall` | Wipe all files in volume |
| `renvol <old> <new>` | `mvdir` | Rename volume |
| `copyvol <src> <dst>` / `copyvoli <idx> <dst>` | `cpvol` | Copy volume |
| `copypart <src> <dst>` | `cppart` | Copy all volumes of a partition |
| `setosvervol <ver>` / `setlnum <num>` | — | Set volume OS version / load number |
| `fixramname <path>` / `fixramnameall` | — | Fix file name headers |
### Volume Parameters
| Command | Alias | Description |
|---------|-------|-------------|
| `lsparam` / `lsparami <idx>` | — | List parameters |
| `initparam` / `initparami <idx>` | — | Initialize parameters |
| `setparam <idx> <val>` / `setparami <vidx> <pidx> <val>` | — | Set parameter |
| `getparam <file>` / `putparam <file>` | `paramget` / `paramput` | Export/import parameters |
### Tag Management
| Command | Description |
|---------|-------------|
| `lstags` | List tags |
| `inittags` | Initialize all tags |
| `rentag <idx> <name>` | Rename a tag |
| `settagi <file-idx> <tag-idx>` / `settagall <tag-idx>` | Tag a file / all files |
| `clrtagi <file-idx> <tag-idx or all>` / `clrtagall <tag or all>` | Untag |
| `setfiltertag <idx>` / `clrfiltertag <idx or all>` | Filter by tag |
### Formatting / Filesystem Operations
| Command | Description |
|---------|-------------|
| `formatfloppyl9` / `l1` / `l3` | Format low-density floppy for S900/S1000/S3000 |
| `formatfloppyh9` / `h1` / `h3` | Format high-density floppy |
| `wipefloppy` | Create filesystem on floppy |
| `formatharddisk9 [<size>]` | Format HD for S900 (SH205, SUPRA20M, SUPRA30M, SUPRA60M, or size) |
| `formatharddisk1 [<part-size> [<total-size>]]` | Format HD for S1000 |
| `formatharddisk3 [<part-size> [<total-size>]]` | Format HD for S3000 |
| `formatharddisk3cd [<part-size> [<total-size>]]` | Format CD3000 CD-ROM |
| `wipepart` / `wipepart3cd` | Create filesystem in partition |
| `fixpart` / `fixharddisk` | Fix filesystem |
| `scanbadblkspart` / `scanbadblksdisk` | Scan for bad blocks |
| `markbadblkspart` / `markbadblksdisk` | Mark free bad blocks |
| `setcdinfo [<label>]` / `cdinfo` / `vcdinfo` | CD3000 CD-ROM info |
### FAT / Direct-to-Disk Takes
| Command | Alias | Description |
|---------|-------|-------------|
| `tinfoi <idx>` / `tinfoall` | — | DD take info |
| `tdeli <idx>` | `trmi` | Delete DD take |
| `treni <idx> <name>` | `tmvi` | Rename DD take |
| `tgeti <idx>` / `tgetall` | `texporti` | Export DD take (`.TK`) |
| `tput <file>` | `timport` | Import DD take (`*.TK` for all) |
| `take2wavi <idx>` / `take2wavall` | `t2wavi`, `getwavti` | DD take → WAV |
| `wav2take <file>` | `wav2t`, `putwavt` | WAV → DD take |
### Tar Archives
| Command | Alias | Description |
|---------|-------|-------------|
| `tarc <file>` | `gettar` | Create tar from current directory |
| `tarcwav <file>` | `gettarwav` | Tar-create with WAV conversion |
| `tarx <file>` | `puttar` | Extract tar (auto-detect type) |
| `tarx9` / `tarx1` / `tarx3` / `tarx3cd` | `puttar9` etc. | Extract as specific type |
| `tarxwav` | `puttarwav` | Extract with WAV → sample conversion |
| `tarxwav9` / `tarxwav9c` / `tarxwav1` / `tarxwav3` | — | Extract WAV as specific sampler type |
## Filesystem Types
| Type | Description | Block Size | Max Size / Blocks |
|------|-------------|------------|-------------------|
| FLL | Low-density floppy | 1 KB | 800 KB (800 blocks) |
| FLH | High-density floppy | 1 KB | 1600 KB (1600 blocks) |
| HD9 | S900/S950 harddisk | 8 KB | ~64 MB (8191 blocks) |
| HD | S1000/S3000 partition | 8 KB | 60 MB/partition, ~512 MB total |
| DD | S1100/S3000 Direct-to-Disk | 8 KB | ~512 MB |
## Build
```bash
make
```
Produces the `akaiutil` binary.
+3
View File
@@ -0,0 +1,3 @@
module akai-fetch
go 1.26
+596
View File
@@ -0,0 +1,596 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"net/http"
"net/url"
"os"
"os/exec"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"time"
)
const (
iaSearchURL = "https://archive.org/advancedsearch.php"
iaBaseURL = "https://archive.org"
userAgent = "akai-fetch/1.0"
)
type SearchResult struct {
Response struct {
NumFound int `json:"numFound"`
Docs []SearchDoc `json:"docs"`
} `json:"response"`
}
type SearchDoc struct {
Identifier string `json:"identifier"`
Title string `json:"title"`
Downloads int `json:"downloads"`
Format []string `json:"format"`
}
type MetadataResult struct {
Files []MetadataFile `json:"files"`
}
type MetadataFile struct {
Name string `json:"name"`
Size string `json:"size"`
Format string `json:"format"`
Source string `json:"source"`
}
func main() {
if len(os.Args) < 2 {
printUsage()
os.Exit(1)
}
cmd := os.Args[1]
args := os.Args[2:]
switch cmd {
case "search":
cmdSearch(args)
case "list":
cmdList(args)
case "download":
cmdDownload(args)
case "extract":
cmdExtract(args)
case "pipeline":
cmdPipeline(args)
default:
fmt.Fprintf(os.Stderr, "unknown command: %s\n", cmd)
printUsage()
os.Exit(1)
}
}
func printUsage() {
fmt.Println(`akai-fetch — AKAI sampler ISO downloader & extractor
Usage:
akai-fetch search [flags] search archive.org for AKAI sampler ISOs
akai-fetch list <identifier> list downloadable ISO files in an item
akai-fetch download [flags] download ISOs (from file or by identifier)
akai-fetch extract [flags] extract WAVs from downloaded ISOs
akai-fetch pipeline [flags] full search → download → extract pipeline
Search flags:
-query "akai sampler" search query (default: "subject:akai AND subject:sampler")
-filter "term" extra term AND-ed onto the query (e.g. "vocal")
-limit 30 max results (default: 30)
-min-downloads 0 minimum download count filter
Download flags:
-i "identifier" archive.org item identifier
-f "file.txt" file with list of identifiers (one per line)
-dir "./isos" output directory (default: current dir)
-jobs 2 concurrent downloads (default: 2)
Extract flags:
-dir "./isos" directory containing ISO files
-out "./wavs" output directory for WAV files
-tool "./extract_wavs.sh" path to extraction script
-jobs 2 concurrent extractions (default: 2)
Pipeline flags:
-query "akai sampler" search query (default: "subject:akai AND subject:sampler")
-filter "term" extra term AND-ed onto the query
-limit 30 max results
-dir "./output" base output directory
-download-jobs 2 concurrent downloads
-extract-jobs 2 concurrent extractions`)
}
// ─── Search ────────────────────────────────────────────────────────────
func cmdSearch(args []string) {
fs := flag.NewFlagSet("search", flag.ExitOnError)
query := fs.String("query", "subject:akai AND subject:sampler", "search query")
filter := fs.String("filter", "", "extra term AND-ed onto the query")
limit := fs.Int("limit", 30, "max results")
minDL := fs.Int("min-downloads", 0, "minimum download count")
_ = fs.Parse(args)
q := *query
if *filter != "" {
q = "(" + q + ") AND (" + *filter + ")"
}
results := searchArchive(q, *limit)
sort.Slice(results, func(i, j int) bool {
return results[i].Downloads > results[j].Downloads
})
fmt.Printf("Found %d items:\n\n", len(results))
for _, r := range results {
if *minDL > 0 && r.Downloads < *minDL {
continue
}
fmt.Printf(" %-40s downloads: %-8d title: %s\n", r.Identifier, r.Downloads, truncate(r.Title, 50))
}
}
func searchArchive(query string, limit int) []SearchDoc {
params := url.Values{}
params.Set("q", query)
params.Set("fl[]", "identifier,title,downloads,format")
params.Set("sort[]", "downloads desc")
params.Set("rows", strconv.Itoa(limit))
params.Set("page", "1")
params.Set("output", "json")
u := iaSearchURL + "?" + params.Encode()
client := &http.Client{Timeout: 30 * time.Second}
req, err := http.NewRequest("GET", u, nil)
if err != nil {
fatal("http request: %v", err)
}
req.Header.Set("User-Agent", userAgent)
resp, err := client.Do(req)
if err != nil {
fatal("search request: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fatal("read response: %v", err)
}
var sr SearchResult
if err := json.Unmarshal(body, &sr); err != nil {
fatal("parse response: %v", err)
}
return sr.Response.Docs
}
// ─── List ──────────────────────────────────────────────────────────────
func cmdList(args []string) {
if len(args) < 1 {
fatal("usage: akai-fetch list <identifier>")
}
identifier := args[0]
files := getItemFiles(identifier)
fmt.Printf("Files in %s:\n\n", identifier)
for _, f := range files {
size := f.Size
if size == "" {
size = "?"
}
fmt.Printf(" %-60s %s\n", f.Name, size)
}
}
func getItemFiles(identifier string) []MetadataFile {
u := fmt.Sprintf("%s/metadata/%s", iaBaseURL, url.PathEscape(identifier))
client := &http.Client{Timeout: 30 * time.Second}
req, _ := http.NewRequest("GET", u, nil)
req.Header.Set("User-Agent", userAgent)
resp, err := client.Do(req)
if err != nil {
fatal("metadata request: %v", err)
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fatal("read metadata: %v", err)
}
var mr struct {
Files []MetadataFile `json:"files"`
}
if err := json.Unmarshal(body, &mr); err != nil {
fatal("parse metadata: %v", err)
}
var isos []MetadataFile
for _, f := range mr.Files {
if strings.HasSuffix(strings.ToLower(f.Name), ".iso") {
isos = append(isos, f)
}
}
return isos
}
// ─── Download ──────────────────────────────────────────────────────────
type downloadJob struct {
Identifier string
Name string
URL string
OutPath string
Size int64
}
func cmdDownload(args []string) {
fs := flag.NewFlagSet("download", flag.ExitOnError)
identifier := fs.String("i", "", "archive.org item identifier")
idFile := fs.String("f", "", "file with identifiers (one per line)")
outDir := fs.String("dir", ".", "output directory")
jobs := fs.Int("jobs", 2, "concurrent downloads")
_ = fs.Parse(args)
os.MkdirAll(*outDir, 0755)
var identifiers []string
if *identifier != "" {
identifiers = append(identifiers, *identifier)
}
if *idFile != "" {
data, err := os.ReadFile(*idFile)
if err != nil {
fatal("read id file: %v", err)
}
for _, line := range strings.Split(string(data), "\n") {
line = strings.TrimSpace(line)
if line != "" && !strings.HasPrefix(line, "#") {
identifiers = append(identifiers, line)
}
}
}
if len(identifiers) == 0 {
fatal("provide -i <identifier> or -f <file>")
}
var jobsList []downloadJob
for _, id := range identifiers {
files := getItemFiles(id)
if len(files) == 0 {
fmt.Printf("[%s] no ISO files found\n", id)
continue
}
for _, f := range files {
size, _ := strconv.ParseInt(f.Size, 10, 64)
jobsList = append(jobsList, downloadJob{
Identifier: id,
Name: f.Name,
URL: fmt.Sprintf("%s/download/%s/%s", iaBaseURL, url.PathEscape(id), url.PathEscape(f.Name)),
OutPath: filepath.Join(*outDir, f.Name),
Size: size,
})
}
}
if len(jobsList) == 0 {
fmt.Println("no download jobs")
return
}
fmt.Printf("Downloading %d file(s) with %d concurrent job(s)...\n\n", len(jobsList), *jobs)
var mu sync.Mutex
sem := make(chan struct{}, *jobs)
var wg sync.WaitGroup
var totalDownloaded int64
for _, job := range jobsList {
wg.Add(1)
go func(j downloadJob) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
size, err := downloadFile(j)
mu.Lock()
totalDownloaded += size
mu.Unlock()
if err != nil {
fmt.Printf(" FAIL %-40s %v\n", j.Name, err)
} else {
fmt.Printf(" OK %-40s %s\n", j.Name, humanSize(size))
}
}(job)
}
wg.Wait()
fmt.Printf("\nDownloaded %s total\n", humanSize(totalDownloaded))
}
func downloadFile(job downloadJob) (int64, error) {
// Check if file already exists and has the expected size
if fi, err := os.Stat(job.OutPath); err == nil {
if job.Size > 0 && fi.Size() == job.Size {
return fi.Size(), nil
}
}
// Check if partial file exists for resume
var existingSize int64
if fi, err := os.Stat(job.OutPath); err == nil {
existingSize = fi.Size()
}
client := &http.Client{Timeout: 0}
req, err := http.NewRequest("GET", job.URL, nil)
if err != nil {
return 0, fmt.Errorf("request: %w", err)
}
req.Header.Set("User-Agent", userAgent)
if existingSize > 0 {
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", existingSize))
}
resp, err := client.Do(req)
if err != nil {
return 0, fmt.Errorf("get: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusPartialContent {
return 0, fmt.Errorf("HTTP %d", resp.StatusCode)
}
outFile, err := os.OpenFile(job.OutPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return 0, fmt.Errorf("open: %w", err)
}
defer outFile.Close()
written, err := io.Copy(outFile, resp.Body)
if err != nil {
return 0, fmt.Errorf("download: %w", err)
}
return written + existingSize, nil
}
// ─── Extract ───────────────────────────────────────────────────────────
func cmdExtract(args []string) {
fs := flag.NewFlagSet("extract", flag.ExitOnError)
isoDir := fs.String("dir", ".", "directory with ISO files")
outDir := fs.String("out", "./wavs", "output directory for WAVs")
toolPath := fs.String("tool", "./extract_wavs.sh", "path to extraction script")
jobs := fs.Int("jobs", 2, "concurrent extractions")
_ = fs.Parse(args)
entries, err := os.ReadDir(*isoDir)
if err != nil {
fatal("read dir: %v", err)
}
var isos []string
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(strings.ToLower(e.Name()), ".iso") {
isos = append(isos, filepath.Join(*isoDir, e.Name()))
}
}
if len(isos) == 0 {
fmt.Println("no ISO files found in", *isoDir)
return
}
fmt.Printf("Extracting %d ISO(s) with %d concurrent job(s)...\n", len(isos), *jobs)
sem := make(chan struct{}, *jobs)
var wg sync.WaitGroup
var mu sync.Mutex
results := map[string]string{}
for _, iso := range isos {
wg.Add(1)
go func(isoPath string) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
out := *outDir
result, err := extractISO(*toolPath, isoPath, out)
mu.Lock()
results[filepath.Base(isoPath)] = result
mu.Unlock()
if err != nil {
fmt.Printf(" FAIL %-40s %v\n", filepath.Base(isoPath), err)
} else {
fmt.Printf(" OK %-40s %s\n", filepath.Base(isoPath), result)
}
}(iso)
}
wg.Wait()
}
func extractISO(toolPath, isoPath, outDir string) (string, error) {
absTool, err := filepath.Abs(toolPath)
if err != nil {
return "", err
}
if _, err := os.Stat(absTool); os.IsNotExist(err) {
return "", fmt.Errorf("script not found: %s", absTool)
}
isoOutDir := filepath.Join(outDir, sanitiseISOName(filepath.Base(isoPath)))
if _, err := os.Stat(isoOutDir); err == nil {
var wavCount int
filepath.WalkDir(isoOutDir, func(p string, d os.DirEntry, err error) error {
if err == nil && !d.IsDir() && strings.HasSuffix(strings.ToLower(d.Name()), ".wav") {
wavCount++
}
return nil
})
if wavCount > 0 {
return fmt.Sprintf("skipped (%d WAVs exist)", wavCount), nil
}
}
cmd := exec.Command("bash", absTool, isoPath, outDir)
cmd.Stderr = nil
output, err := cmd.Output()
if err != nil {
return "", fmt.Errorf("extract: %w", err)
}
lines := strings.Split(string(output), "\n")
for _, line := range lines {
if strings.Contains(line, "Total WAV files:") {
return strings.TrimSpace(line), nil
}
}
return "extracted (check output)", nil
}
func sanitiseISOName(path string) string {
name := path
if ext := filepath.Ext(name); ext != "" {
name = name[:len(name)-len(ext)]
}
// Matches extract_wavs.sh sanitisation
var buf strings.Builder
for _, r := range name {
if r == ' ' {
buf.WriteRune('_')
} else if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') ||
(r >= '0' && r <= '9') || r == '_' || r == '.' || r == '-' {
buf.WriteRune(r)
} else {
buf.WriteRune('_')
}
}
// Collapse multiple underscores
s := buf.String()
for strings.Contains(s, "__") {
s = strings.ReplaceAll(s, "__", "_")
}
// Strip leading/trailing _ and .
s = strings.Trim(s, "_.")
return s
}
// ─── Pipeline ──────────────────────────────────────────────────────────
func cmdPipeline(args []string) {
fs := flag.NewFlagSet("pipeline", flag.ExitOnError)
query := fs.String("query", "subject:akai AND subject:sampler", "search query")
filter := fs.String("filter", "", "extra term AND-ed onto the query")
limit := fs.Int("limit", 10, "max results")
baseDir := fs.String("dir", "./output", "base output directory")
dlJobs := fs.Int("download-jobs", 2, "concurrent downloads")
extJobs := fs.Int("extract-jobs", 2, "concurrent extractions")
_ = fs.Parse(args)
isoDir := filepath.Join(*baseDir, "isos")
wavDir := filepath.Join(*baseDir, "wavs")
toolPath := filepath.Join(filepath.Dir(os.Args[0]), "extract_wavs.sh")
if _, err := os.Stat(toolPath); os.IsNotExist(err) {
cwd, _ := os.Getwd()
toolPath = filepath.Join(cwd, "extract_wavs.sh")
}
// Remaining args after flags are treated as explicit identifiers
identifiers := fs.Args()
if len(identifiers) == 0 {
fmt.Println("=== Phase 1: Search ===")
q := *query
if *filter != "" {
q = "(" + q + ") AND (" + *filter + ")"
}
fmt.Printf("Query: %s Limit: %d\n\n", q, *limit)
results := searchArchive(q, *limit)
sort.Slice(results, func(i, j int) bool {
return results[i].Downloads > results[j].Downloads
})
if len(results) == 0 {
fmt.Println("No results found.")
return
}
for _, r := range results {
identifiers = append(identifiers, r.Identifier)
}
fmt.Printf("Found %d items\n\n", len(identifiers))
} else {
fmt.Printf("=== Processing %d specific item(s) ===\n\n", len(identifiers))
}
if err := os.MkdirAll(*baseDir, 0755); err != nil {
fatal("create output dir: %v", err)
}
idFile := filepath.Join(*baseDir, "identifiers.txt")
var idContent strings.Builder
for _, id := range identifiers {
idContent.WriteString(id + "\n")
}
if err := os.WriteFile(idFile, []byte(idContent.String()), 0644); err != nil {
fatal("write ids: %v", err)
}
fmt.Printf("Identifiers saved to %s\n\n", idFile)
fmt.Println("=== Phase 2: Download ===")
cmdDownload([]string{"-f", idFile, "-dir", isoDir, "-jobs", fmt.Sprintf("%d", *dlJobs)})
fmt.Println("\n=== Phase 3: Extract ===")
cmdExtract([]string{"-dir", isoDir, "-out", wavDir, "-tool", toolPath, "-jobs", fmt.Sprintf("%d", *extJobs)})
fmt.Printf("\n=== Pipeline Complete ===\n")
fmt.Printf(" ISOs: %s\n", isoDir)
fmt.Printf(" WAVs: %s\n", wavDir)
}
// ─── Helpers ───────────────────────────────────────────────────────────
func fatal(format string, args ...any) {
fmt.Fprintf(os.Stderr, "error: "+format+"\n", args...)
os.Exit(1)
}
func truncate(s string, n int) string {
if len(s) <= n {
return s
}
return s[:n-3] + "..."
}
func humanSize(bytes int64) string {
const unit = 1024
if bytes < unit {
return fmt.Sprintf("%dB", bytes)
}
div, exp := int64(unit), 0
for n := bytes / unit; n >= unit; n /= unit {
div *= unit
exp++
}
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}
func init() {
// Ensure we can parse flags even with -count or other test flags
flag.CommandLine.Parse([]string{})
}
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env bash
# Extract all AKAI samples as WAV from all volumes in an AKAI disk image.
# Usage: ./extract_wavs.sh <iso-file> [output-dir]
# Uses a single akaiutil session to avoid repeated disk rescans.
set -euo pipefail
AKAIUTIL="${AKAIUTIL:-akaiutil}"
ISO="${1:?Usage: $0 <iso-file> [output-dir]}"
OUTPUT="${2:-wavs}"
# Derive ISO basename without extension, sanitized for filesystem use
isobase=$(basename "$ISO")
isobase="${isobase%.*}"
isobase=$(echo "$isobase" | sed 's/ /_/g' | sed 's/[^A-Za-z0-9_.-]/_/g' | sed 's/__*/_/g' | sed 's/^[_.]//; s/[_.]$//')
OUTPUT="$OUTPUT/$isobase"
TMPFILE=$(mktemp /tmp/akai_cmds.XXXXXX)
trap 'rm -f "$TMPFILE"' EXIT
mkdir -p "$OUTPUT"
# Phase 1: enumerate partitions from df output
echo "Enumerating partitions and volumes..."
DF_OUTPUT=$("$AKAIUTIL" -r "$ISO" 2>/dev/null <<< $'df\nq')
# Parse partition letters from the partition table in df output
PARTITIONS=()
while IFS= read -r line; do
if [[ "$line" =~ ^[[:space:]]+([A-Z])[[:space:]]+ ]]; then
PARTITIONS+=("${BASH_REMATCH[1]}")
fi
done <<< "$DF_OUTPUT"
if [[ ${#PARTITIONS[@]} -eq 0 ]]; then
echo "No partitions found in ISO. Trying single-partition layout..."
PARTITIONS=("A")
fi
echo "Found partitions: ${PARTITIONS[*]}"
# Scan each partition for volumes
VOLUME_LIST=$(
{
for p in "${PARTITIONS[@]}"; do
echo "cd /disk0/$p"
echo "dir"
done
echo "q"
} | "$AKAIUTIL" -r "$ISO" 2>/dev/null
)
# Parse partition-letter:volume-name pairs
VOLUMES=()
CURRENT_PART=""
while IFS= read -r line; do
for p in "${PARTITIONS[@]}"; do
if [[ "$line" == *"/disk0/$p >"* ]]; then
CURRENT_PART="$p"
fi
done
if [[ "$line" =~ ^[[:space:]]+[0-9]+[[:space:]]+(.+)[[:space:]]+-[[:space:]]+ ]]; then
name="${BASH_REMATCH[1]}"
name="${name%% -*}"
name="$(echo "$name" | sed 's/ *$//')"
if [[ -n "$CURRENT_PART" && -n "$name" ]]; then
VOLUMES+=("$CURRENT_PART|$name")
fi
fi
done <<< "$VOLUME_LIST"
echo "Found ${#VOLUMES[@]} volumes"
# Phase 2: build command file and create output dirs
> "$TMPFILE"
for entry in "${VOLUMES[@]}"; do
IFS='|' read -r part vol_name <<< "$entry"
safe_name=$(echo "$vol_name" | sed 's/ /_/g' | sed 's/[^A-Za-z0-9_.-]/_/g' | sed 's/__*/_/g' | sed 's/^[_.]//; s/[_.]$//')
[[ -z "$safe_name" ]] && safe_name="volume"
vol_dir="$OUTPUT/$safe_name"
mkdir -p "$vol_dir"
nav_name="${vol_name// /_}"
echo "lcd $vol_dir" >> "$TMPFILE"
echo "cd /disk0/$part/$nav_name" >> "$TMPFILE"
echo "sample2wavall" >> "$TMPFILE"
done
echo "lcd /" >> "$TMPFILE"
echo "q" >> "$TMPFILE"
# Phase 3: run extraction
echo "Starting extraction..."
START=$SECONDS
"$AKAIUTIL" -r "$ISO" < "$TMPFILE" 2>/dev/null > /tmp/akai_output.txt
DURATION=$((SECONDS - START))
total=0
while IFS= read -r line; do
if [[ "$line" =~ exported[[:space:]]+([0-9]+)[[:space:]]+file ]]; then
count="${BASH_REMATCH[1]}"
total=$((total + count))
echo " -> $count WAVs"
fi
done < /tmp/akai_output.txt
echo ""
echo "--- Done in ${DURATION}s ---"
echo "Total WAV files: $total"
echo ""
echo "WAVs are in: $OUTPUT/"
+76
View File
@@ -0,0 +1,76 @@
# Copyright (c) 2008-2022 Klaus Michael Indlekofer. All rights reserved.
#
# m.indlekofer@gmx.de
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
VERSION = 4.6.7
CFLAGS += -Wall -Wextra -O2
ifdef FILE_OFFSET_BITS_64
CFLAGS += -D_FILE_OFFSET_BITS=64
endif
all: akaiutil
install:
$(INSTALL_PROGRAM) akaiutil $(PREFIX)/bin/
clean:
rm -f akaiutil akaiutil.exe *.o *.obj
back:
mkdir -p akaiutil-$(VERSION);\
cp -p Makefile Makefile.nmake README.txt gpl*.txt *.c *.h *.vcproj *.sln *.dsw *.dsp akaiutil-$(VERSION);\
tar -clvpzf akaiutil-$(VERSION).tar.gz akaiutil-$(VERSION)
akaiutil: akaiutil_main.o akaiutil_tar.o akaiutil_file.o akaiutil_take.o akaiutil_wav.o akaiutil.o akaiutil_io.o commonlib.o
$(CC) $(CFLAGS) -o $@ akaiutil_main.o akaiutil_tar.o akaiutil_file.o akaiutil_take.o akaiutil_wav.o akaiutil.o akaiutil_io.o commonlib.o -lm
akaiutil_main.o: akaiutil_main.c akaiutil.h akaiutil_io.h akaiutil_tar.h akaiutil_file.h akaiutil_take.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_main.c
akaiutil_tar.o: akaiutil_tar.c akaiutil_tar.h akaiutil_file.h akaiutil_take.h akaiutil.h akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_tar.c
akaiutil_file.o: akaiutil_file.c akaiutil_file.h akaiutil_wav.h akaiutil.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_file.c
akaiutil_take.o: akaiutil_take.c akaiutil_take.h akaiutil_wav.h akaiutil.h akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_take.c
akaiutil_wav.o: akaiutil_wav.c akaiutil_wav.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_wav.c
akaiutil.o: akaiutil.c akaiutil.h akaiutil_io.h akaiutil_file.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil.c
akaiutil_io.o: akaiutil_io.c akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) -c akaiutil_io.c
commonlib.o: commonlib.c commoninclude.h
$(CC) $(CFLAGS) -c commonlib.c
# EOF
+63
View File
@@ -0,0 +1,63 @@
# Copyright (c) 2008-2021 Klaus Michael Indlekofer. All rights reserved.
#
# m.indlekofer@gmx.de
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
CFLAGS = $(CFLAGS) /nologo /O2 /D_VISUALCPP /D_CRT_SECURE_NO_DEPRECATE
LIBS = $(LIBS) Winmm.lib
all: akaiutil.exe
clean:
del /q /f akaiutil.exe *.obj
akaiutil.exe: akaiutil_main.obj akaiutil_tar.obj akaiutil_file.obj akaiutil_take.obj akaiutil_wav.obj akaiutil.obj akaiutil_io.obj commonlib.obj
$(CC) $(CFLAGS) /Fe$@ akaiutil_main.obj akaiutil_tar.obj akaiutil_file.obj akaiutil_take.obj akaiutil_wav.obj akaiutil.obj akaiutil_io.obj commonlib.obj $(LIBS)
akaiutil_main.obj: akaiutil_main.c akaiutil.h akaiutil_io.h akaiutil_tar.h akaiutil_file.h akaiutil_take.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_main.c
akaiutil_tar.obj: akaiutil_tar.c akaiutil_tar.h akaiutil_file.h akaiutil_take.h akaiutil.h akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_tar.c
akaiutil_file.obj: akaiutil_file.c akaiutil_file.h akaiutil_wav.h akaiutil.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_file.c
akaiutil_take.obj: akaiutil_take.c akaiutil_take.h akaiutil_wav.h akaiutil.h akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_take.c
akaiutil_wav.obj: akaiutil_wav.c akaiutil_wav.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_wav.c
akaiutil.obj: akaiutil.c akaiutil.h akaiutil_io.h akaiutil_file.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil.c
akaiutil_io.obj: akaiutil_io.c akaiutil_io.h commoninclude.h
$(CC) $(CFLAGS) /c akaiutil_io.c
commonlib.obj: commonlib.c commoninclude.h
$(CC) $(CFLAGS) /c commonlib.c
# EOF
+755
View File
@@ -0,0 +1,755 @@
akaiutil: access to AKAI S900/S1000/S3000 filesystems
Copyright (c) 2008-2022 by Klaus Michael Indlekofer. All rights reserved.
Note: Special restrictions apply. See disclaimers below and within the distribution.
Release akaiutil-4.6.7 (21-OCT-2022)
Email: m.indlekofer@gmx.de
Usage:
------
akaiutil [-h] [-r] [-F] [-C] [-l <lock-file>] [-o <start-offset>] [-s <pseudo-disk-size>] [-n <pseudo-disk-number>] [-c <cdrom-index> ...] [-p <physdrive-index> ...] [[-f] <floppy-drive> ...] [[-f] <disk-file> ...]
-h print this info
-r read-only mode
-F disable floppy filesystem for disk-files/CD-ROM drives/physical drives
-C disable cache
-l lock-file
-o set start offset for disk-file/drive in bytes
-s set pseudo-disk size in KB
-n set max. number of pseudo-disks per disk-file/drive
-c CD-ROM drive
-p physical drive
-f floppy drive or disk-file
<floppy-drive> = floppyla: | floppylb: | floppyha: | floppyhb:
Commands:
---------
help [<cmd>] print help information for a command
=man
exit exit program
=quit
=bye
=q
restart restart program (with opened disks)
restartkeep restart program (with opened disks, keep current directory path etc.)
=restart.
=sync
df print disk info
dinfo print current directory info
=pwd
cd [<path>] change current directory
cdi <volume-index> change current volume
dir [<path>] list directory
=ls
dirrec list current directory recursively
=lsrec
lstags list tags in partition
=dirtags
inittags initialize tags of disk or partition
rentag <tag-index> <tag-name> rename tag in partition
cdinfo print CD3000 CD-ROM info
vcdinfo print verbose CD3000 CD-ROM info
setcdinfo [<cdlabel>] set CD3000 CD-ROM info of disk or partition
lcd <dir-path> change current local (external) directory
ldir list files in current local (external) directory
=lls
lsfat print FAT of current partition
lsfati <file-index> print FAT-chain of file
lstfati <take-index> print FAT-chain of DD take
infoi <file-index> print information for file
infoall print information for all files in current volume
tinfoi <take-index> print information for DD take
tinfoall print information for all DD takes in current partition
del <file-path> delete file
=rm
deli <file-index> delete file
rmi
tdeli <take-index> delete DD take
trmi
ren <old-file-path> <new-file-path> [<new-file-index>] rename/move file
=mv
reni <old-file-index> <new-file-path> [<new-file-index>] rename/move file
=mvi
setosveri <file-index> <new-os-version> set OS version of file in S1000/S3000 volume
setosverall <new-os-version> set OS version of all files in current S1000/S3000 volume
setuncompri <file-index> <new-uncompr> set uncompr value of compressed file in S900 volume
updateuncompri <file-index> update uncompr value of compressed file in S900 volume
updateuncomprall update uncompr value of all compressed files in current S900 volume
sample900uncompr <file-path> [<dest-vol-path>] uncompress S900 compressed sample file
=s9uncompr
sample900uncompri <file-index> [<dest-vol-path>] uncompress S900 compressed sample file
=s9uncompri
sample900uncomprall [<dest-vol-path>] uncompress all S900 compressed sample files in current volume
=s9uncomprall
sample900compr <file-path> [<dest-vol-path>] compress S900 non-compressed sample file
=s9compr
sample900compri <file-index> [<dest-vol-path>] compress S900 non-compressed sample file
=s9compri
sample900comprall [<dest-vol-path>] compress all S900 non-compressed sample files in current volume
=s9comprall
fixramname <file-path> fix name in file header
fixramnamei <file-index> fix name in file header
fixramnameall fix name in file header of all files in current volume
clrtagi <file-index> {<tag-index>|all} untag file
clrtagall {<tag-index>|all} untag all files in current volume
settagi <file-index> <tag-index> tag file
settagall <tag-index> tag all files in current volume
treni <take-index> <new-name> rename DD take
=tmvi
clrfiltertag {<tag-index>|all} remove tag from file filter
setfiltertag <tag-index> add tag to file filter
copy <src-file-path> <new-file-path> [<new-file-index>] copy file
=cp
copyi <src-file-index> <new-file-path> [<new-file-index>] copy file
=cpi
copyvol <src-volume-path> <new-volume-path> copy volume (with all of its files)
=cpvol
copyvoli <src-volume-index> <new-volume-path> copy volume (with all of its files)
=cpvoli
copypart <src-partition-path> <dst-partition-path> copy all volumes of a partition
=cppart
copytags <src-partition-path> <dst-partition-path> copy all tags of a partition
=cptags
wipevol <volume-path> delete all files in volume
=wipedir
=rmall
wipevoli <volume-index> delete all files in volume
=wipediri
=rmalli
delvol <volume-path> delete volume and all of its files
=deldir
=rmvol
=rmdir
delvoli <volume-index> delete volume and all of its files
=deldiri
=rmvoli
=rmdiri
formatfloppyl9 format/erase low-density floppy for S900/S950, create filesystem
=formatfl9
formatfloppyl1 format/erase low-density floppy for S1000, create filesystem
=formatfl1
formatfloppyl3 format/erase low-density floppy for S3000, create filesystem
=formatfl3
formatfloppyh9 format/erase high-density floppy for S950, create filesystem
=formatfh9
formatfloppyh1 format/erase high-density floppy for S1000, create filesystem
=formatfh1
formatfloppyh3 format/erase high-density floppy for S3000, create filesystem
=formatfh3
wipefloppy create filesystem on floppy
=newfsfloppy
formatharddisk9 [<total-size>[M]|SH205|SUPRA20M|SUPRA30M|SUPRA60M] create filesystem on harddisk for S900/S950 (size in blocks or MB, or drive name)
=formathd9
=newfsharddisk9
=newfshd9
formatharddisk1 [<part-size>[M] [<total-size>[M]]] create filesystem on harddisk for S1000 (size in blocks or MB)
=formathd1
=newfsharddisk9
=newfshd1
formatharddisk3 [<part-size>[M] [<total-size>[M]]] create filesystem on harddisk for S3000 or CD3000 (size in blocks or MB)
=formathd3
=newfsharddisk3
=newfshd3
formatharddisk3cd [<part-size>[M] [<total-size>[M]]] create filesystem on harddisk for CD3000 CD-ROM (size in blocks or MB)
=formatcd
=newfsharddisk3cd
=newfscd
wipepart [<partition-path>] create filesystem in harddisk partition
=newfspart
wipepart3cd [<partition-path>] create filesystem in harddisk partition for CD3000 CD-ROM
=newfspart3cd
fixpart [<partition-path>] fix filesystem in harddisk partition
fixharddisk [<disk-path>] fix filesystem on harddisk
scanbadblkspart [<partition-path>] scan for bad blocks/clusters in partition
markbadblkspart [<partition-path>] mark free bad blocks/clusters in partition
scanbadblksdisk [<disk-path>] scan for bad blocks/clusters in all partitions of disk
markbadblksdisk [<disk-path>] mark free bad blocks/clusters in all partitions of disk
getdisk <file-name> get disk (to external file)
=dget
=dexport
putdisk <file-name> put disk (from external file)
=dput
=dimport
getpart [<partition-path>] <file-name> get partition (to external file)
=pget
=pexport
putpart <file-name> [<partition-path>] put partition (from external file)
=pput
=pimport
gettags <file-name> get tags from partition (to external file)
=tagsget
=tagsexport
puttags <file-name> put tags to partition (from external file)
=tagsput
=tagsimport
renvol <old-path> <new-name> rename volume
=rendir
=mvvol
=mvdir
renvoli <volume-index> <new-name> rename volume
=rendiri
=mvvoli
=mvdiri
setosvervol <new-os-version> set OS version of current volume
setosvervoli <volume-index> <new-os-version> set OS version of volume
setlnum <new-load-number> set load number of current volume (OFF for none)
setlnumi <volume-index> <new-load-number> set load number of volume (OFF for none)
lsparam list parameters in current volume
lsparami <volume-index> list parameters in volume
initparam initialize parameters in current volume
initparami <volume-index> initialize parameters in volume
setparam <par-index> <par-value> set parameters in current volume
setparami <volume-index> <par-index> <par-value> set parameters in volume
getparam <file-name> get parameters from current volume (to external file)
=paramget
=paramexport
getparami <volume-index> <file-name> get parameters from volume (to external file)
=paramgeti
=paramexporti
putparam <file-name> put parameters to current volume (from external file)
=paramput
=paramimport
putparami <volume-index> <file-name> put parameters to volume (from external file)
=paramputi
=paramimporti
get <file-path> [<begin-byte> [<end-byte>]] get file (to external)
=export
geti <file-index> [<begin-byte> [<end-byte>]] get file (to external)
=exporti
getall get all files (to external)
=exportall
sample2wav <file-path> convert sample file into external WAV file
=s2wav
=getwav
sample2wavi <file-index> convert sample file into external WAV file
=s2wavi
=getwavi
sample2wavall convert all sample files into external WAV files
=s2wavall
=getwavall
put [<volume-path>/]<file-name> [<file-index>] put file (from external, use * for all local files)
=import
wav2sample [<volume-path>/]<wav-file> [<file-index>] convert external WAV file into sample file (use *.wav for all local WAV files)
=wav2s
=putwav
wav2sample9 [<volume-path>/]<wav-file> [<file-index>] convert external WAV file into S900 non-compressed sample file (use *.wav for all local WAV files)
=wav2s9
=putwav9
wav2sample9c [<volume-path>/]<wav-file> [<file-index>] convert external WAV file into S900 compressed sample file (use *.wav for all local WAV files)
=wav2s9c
=putwav9c
wav2sample1 [<volume-path>/]<wav-file> [<file-index>] convert external WAV file into S1000 sample file (use *.wav for all local WAV files)
=wav2s1
=putwav1
wav2sample3 [<volume-path>/]<wav-file> [<file-index>] convert external WAV file into S3000 sample file (use *.wav for all local WAV files)
=wav2s3
=putwav3
tgeti <take-index> get DD take (to external)
=texporti
tgetall get all DD takes (to external)
=texportall
take2wavi <take-index> convert DD take into external WAV file
=t2wavi
=tgetwavi
=getwavti
take2wavall convert all DD takes into external WAV files
=t2wavall
=tgetwavall
=getwavtall
tput <take-file> put DD take (from external, use *.TK for all local DD take files)
=timport
wav2take <wav-file> convert external WAV file into DD take (use *.wav for all local WAV files)
=wav2t
=tputwav
=putwavt
tarc <tar-file> tar c from current directory (to external)
=target
=gettar
tarcwav <tar-file> tar c from current directory (to external) with WAV conversion
=targetwav
=gettarwav
tarx <tar-file> tar x in current directory (from external)
=tarput
=puttar
tarx9 <tar-file> tar x in current directory (from external) for S900
=tarput9
=puttar9
tarx1 <tar-file> tar x in current directory (from external) for S1000
=tarput1
=puttar1
tarx3 <tar-file> tar x in current directory (from external) for S3000 or CD3000
=tarput3
=puttar3
tarx3cd <tar-file> tar x in current directory (from external) for CD3000 CD-ROM
=tarput3cd
=puttar3cd
tarxwav <tar-file> tar x in current directory (from external) with WAV conversion
=tarputwav
=puttarwav
tarxwav9 <tar-file> tar x in current directory (from external) with WAV conversion to S900 non-compressed sample
=tarputwav9
=puttarwav9
tarxwav9c <tar-file> tar x in current directory (from external) with WAV conversion to S900 compressed sample
=tarputwav9c
=puttarwav9c
tarxwav1 <tar-file> tar x in current directory (from external) with WAV conversion to S1000 sample
=tarputwav1
=puttarwav1
tarxwav3 <tar-file> tar x in current directory (from external) with WAV conversion to S3000 sample
=tarputwav3
=puttarwav3
mkvol [<volume-path>] create new volume
=mkdir
mkvol9 [<volume-path>] create new volume for S900
=mkdir9
mkvol1 [<volume-path> [<load-number>]] create new volume for S1000
=mkdir1
mkvol3 [<volume-path> [<load-number>]] create new volume for S3000 or CD3000
=mkdir3
mkvol3cd [<volume-path> [<load-number>]] create new volume for CD3000 CD-ROM
=mkdir3cd
mkvoli <volume-index> [<volume-name> [<load-number>]] create new volume at index
=mkdiri
mkvoli9 <volume-index> [<volume-name>] create new volume for S900 at index
=mkdiri9
mkvoli1 <volume-index> [<volume-name> [<load-number>]] create new volume for S1000 at index
=mkdiri1
mkvoli3 <volume-index> [<volume-name> [<load-number>]] create new volume for S3000 or CD3000 at index
=mkdiri3
mkvoli3cd <volume-index> [<volume-name> [<load-number>]] create new volume for CD3000 CD-ROM
=mkdiri3cd
dircache print cache information
=lscache
disablecache disable cache
enablecache enable cache
lock acquire lock
unlock release lock
playwav [<wav-file>] start playback of current external WAV file
=p
stopwav stop playback of current external WAV file
=s
delwav delete current external WAV file
=rmwav
Examples:
---------
Example 1: access floppy image fff.img
akaiutil.exe fff.img
Example 2: access harddisk images hhh1.img and hhh2.img
akaiutil.exe hhh1.img hhh2.img
Example 3: access harddisk image hhh.img and floppy image fff.img
akaiutil.exe hhh.img fff.img
Example 4: access multi-harddisk image mmm.img with pseudo-disks of 524280KB
akaiutil.exe -s 524280 mmm.img
Example 5: access high-density (HD) floppy in floppy drive A: on Windows PC:
akaiutil.exe floppyha:
Example 6: access Windows physical drive 1 and Windows CD-ROM drive 0
akaiutil.exe -p 1 -c 0
Example 7: access Windows physical drive 2, harddisk image hhh.img, and floppy image fff.img
akaiutil.exe -p 2 hhh.img fff.img
Example 8: access UNIX harddisks /dev/da1, /dev/da2, and harddisk image hhh.img
akaiutil /dev/da1 /dev/da2 hhh.img
Example 9: access Darwin harddisk /dev/disk1
akaiutil /dev/disk1
Example 10: access Darwin CD-ROM /dev/disk2s0 in read-only mode
akaiutil -r /dev/disk2s0
Warning:
--------
Accessing disk-files or floppies or physical drives might destroy their contents!!! Use at your own risk!!!
It is strongly recommended to use the read-only mode (-r) for testing and for accessing valuable drives, floppies, or files.
Notes:
------
* whole (pseudo-)disks can be imported/exported via "putdisk"/"getdisk"
* whole partitions can be imported/exported via "putpart"/"getpart"
* individual files can be imported/exported via "put"/"get"
* sample files can be exported to external WAV files via "sample2wav", "sample2wavall"
* DD takes can be exported to external WAV files via "take2wav", "take2wavall"
* external WAV files can be imported to sample files via "wav2sample", "wav2sample9", "wav2sample1","wav2sample3"
WAV files for sample import must be mono or stereo, and in 8bit or 16bit or 24bit or 32bit PCM format
* external WAV files can be imported to DD takes via "wav2take"
WAV files for DD take import must be mono or stereo, and in 8bit or 16bit or 24bit or 32bit PCM format
* the current external WAV file (e.g. previously exported via "sample2wav" or "take2wav") can be played back via "playwav"
* individual files can be copied via "copy"
* whole volumes and partitions can be copied via "copyvol" and "copypart"
* whole directory trees can be imported/exported from/to tar archives via "tarput"/"target"
* WAV file conversion for tar archives via "tarputwav"/"targetwav"
* file path names in akaiutil are of the form "/disk/partition/volume/file", e.g. "/disk2/C/VOLUME_007/SINE.S"
* for access to files/volumes via index, some commands have an "i" version
* abbreviations:
".." = one level up, "." = stay in same directory
"/N" = "/diskN"
"/floppyN" = "/diskN/A/<volume1>"
'_' can be used as a typable replacement for ' ' (space) in file or volume names
* if the pseudo-disk size ("-s" option) and the max. number of pseudo-disks ("-n" option) are both specified,
the given values are taken and the usable disk size is not determined automatically,
which might be useful e.g. for accessing harddisks which have bad blocks
* for shared access to drives or disk-files,
it might be useful to disable the cache (via the "-C" option or via the "disablecache" command),
and the "restartkeep" command can be used to rescan disks/partitions/volumes,
and a lock-file ("-l" option and "lock"/"unlock" commands) can be used for exclusive access
* for detailed information about individual akaiutil commands please read the online help infos
Floppy drives:
--------------
In order to access a floppy drive to format, read, or write an AKAI floppy on a Windows PC,
fdrawcmd.sys (by Simon Owen, see https://simonowen.com/fdrawcmd/) has to be installed.
Floppy drive arguments for akaiutil running on a Windows PC:
"floppyla:" for low-density (DD) floppy in drive A:
"floppylb:" for low-density (DD) floppy in drive B:
"floppyha:" for high-density (HD) floppy in drive A:
"floppyhb:" for high-density (HD) floppy in drive B:
Formatting drives and images:
-----------------------------
Low-density (DD) floppy size: 800 blocks (1KB) = 800KB
High-density (HD) floppy size: 1600 blocks (1KB) = 1600KB
Max. S900/S950 harddisk (or CD-ROM) size: 8191 blocks (8KB) = 65528KB = approx. 64MB
S900/S950 standard harddisk sizes:
2601 blocks (8KB) = 20808KB ("Atari SH205")
2500 blocks (8KB) = 20000KB ("Supra 20M")
3812 blocks (8KB) = 30496KB ("Supra 30M")
7624 blocks (8KB) = 60992KB ("Supra 60M")
Max. S1000/S3000 harddisk (or CD-ROM) size: 65535 blocks (8KB) = 524280KB = approx. 512MB
S1000/S3000 standard harddisk partition sizes:
3840 blocks (8KB) = 30720KB = 30MB
5120 blocks (8KB) = 40960KB = 40MB
6400 blocks (8KB) = 51200KB = 50MB
7680 blocks (8KB) = 61440KB = 60MB
ZIP100 disk size (as seen by akaiutil): 12288 blocks (8KB) = 98304KB = 96MB
ZIP250 disk size (as seen by akaiutil): 30595 blocks (8KB) = 244760KB = approx. 239MB
Warning: Formatting disk-files or floppies or physical drives destroys their contents!!! Use at your own risk!!!
Example 1: format S900 low-density (DD) floppy in floppy drive A: on Windows PC:
akaiutil.exe floppyla:
-> formatfloppyl9
Example 2: create and format S900 low-density floppy image
dd if=/dev/zero of=fff.img bs=1024 count=800
akaiutil fff.img
-> formatfloppyl9
Example 3: create and format S1000 high-density floppy image
dd if=/dev/zero of=fff.img bs=1024 count=1600
akaiutil fff.img
-> formatfloppyh1
Example 4: create and format CD3000 CD-ROM image of max. size
dd if=/dev/zero of=hhh.img bs=8192 count=65535
akaiutil hhh.img
-> formatharddisk3cd 60M
(this gives 8 partitions of 60MB and 1 partition of approx. 32MB)
-> setcdinfo MYCDROM
(this must be done after all volumes/files have been transferred)
Example 5: create and format S950 harddisk image of max. size
dd if=/dev/zero of=hhh.img bs=8192 count=8191
akaiutil hhh.img
-> formatharddisk9
Example 6: format ZIP100 drive at Windows physical drive 3 for S1000
akaiutil.exe -p 3
-> formatharddisk1 60M
(this gives 1 partition of 60MB and 1 partition of 36MB)
Example 7: format drive at Windows physical drive 4 for S1100 with DD space
akaiutil.exe -p 4
-> formatharddisk1 1M 1M
(this gives 1 partition of 1MB, rest of disk is allocated for DD)
Compilation:
------------
Depending on the operating system and the programming environment,
use Makefile (for make) or Makefile.nmake (for nmake) or the .vcproj file.
References:
-----------
* documentation, manuals, and webpages for AKAI samplers
* floppies, harddisks, CD-ROMs, and files for AKAI samplers
* "AkaiDisk" and its documentation, by Paul Kellett, accessed 09-JAN-2008, 06-MAR-2008, 27-MAR-2010
* "akaitools", by Hiroyuki Ohsaki, accessed 09-JAN-2008
* "akaifs", by Raymond Dresens and Roger Karis, accessed 18-JAN-2008
* "libakai", by Sébastien Métrot and Christian Schoenebeck, accessed 09-JAN-2008
* "fdrawcmd.sys" by Simon Owen, https://simonowen.com/fdrawcmd/, accessed 14-AUG-2020
* "DiskUtil" by Simon Owen, https://simonowen.com/fdrawcmd/DiskUtil.zip, accessed 14-AUG-2020
---
The following holds for all files in this distribution (unless stated otherwise on an
individual basis for each file and statement):
These program/data/document/HTML/picture/media files (materials) are distributed in the
hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. In no event shall the author be
liable for any direct, indirect, incidental, special, exemplary, or consequential damages
(including, but not limited to, procurement of substitue goods or services; loss of use,
data, or profits; or business interruption) however caused and on any theory of liability,
whether in contract, strict liability, or tort (including negligence or otherwise) arising
in any way out of the use of data/information/software from this distribution, even if
advised of the possibility of such damage.
The contents of this distribution are intended for educational, non-commercial purposes
only. Materials contained herein are property of their respective owners.
All brand names and trademarks are property of their respective owners.
If any copyrighted works/trademarks have been used, please contact the author
and the item will be either removed or properly credited (at the copyright/trademark
owner's discretion). We have no intention of violating any copyrights or trademarks.
This distribution might use inlining and deep-linking, i.e. links in this distribution
might lead directly to materials on other web sites/distributions (in which case the
target page normally should be listed/credited in a "links" section). The author does
not take responsibility for the contents of any links referred to. We do not necessarily
endorse, sanction, support, encourage, verify or agree with the contents, opinions or
statements of/on any of the linked pages. These statements hold for all links/references
in all files in this distribution. We are in no way affiliated with any
companies/institutions/individuals which might be mentioned in any manner in this
distribution.
The author does not take responsibility for incorrect, incomplete or misleading information.
Statements are to be considered as the author's free personal opinion. The author does not
necessarly possess any of the items mentioned in files in this distribution.
Files (and the information therein) created by the author are copyright
(c) by the author. Unless protected/restricted otherwise, the author permits
reproduction/redistribution of material contained in this distribution under the condition
that the item is properly credited. Links to items/materials in this distribution are welcome.
Projects/publications/papers that make use of materials, programs, or generated output
of this distribution must properly credit the author and mention the usage of this distribution.
Please contact the author for comments or further questions
and permission to use materials/information from this distribution.
---
This product includes software developed by the University of California, Berkeley
and its contributors.
Copyright (c) 1987-2002 The Regents of the University of California.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. [rescinded 22 July 1999]
4. Neither the name of the University nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
---
End of file
+7254
View File
File diff suppressed because it is too large Load Diff
+674
View File
@@ -0,0 +1,674 @@
#ifndef __AKAIUTIL_H
#define __AKAIUTIL_H
/*
* Copyright (C) 2008,2010,2012,2018,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
/* AKAI S900/S1000/S3000 filesystems */
/* Note: all data types are little endian */
/* floppy */
/* floppy filesystem blocksize */
#define AKAI_FL_BLOCKSIZE 0x0400 /* 1KB */
/* Note: must be == AKAI_FL_SECSIZE (low-level floppy sector size, defined in akaiutil_io.h) */
#if defined(AKAI_FL_SECSIZE)&&(AKAI_FL_BLOCKSIZE!=AKAI_FL_SECSIZE)
#error "AKAI_FL_BLOCKSIZE!=AKAI_FL_SECSIZE"
#endif
#define AKAI_FLL_SIZE 0x0320 /* low-density floppy size in floppy blocks (800KB) */
#define AKAI_FLH_SIZE 0x0640 /* high-density floppy size in floppy blocks (1.6MB) */
/* harddisk */
/* harddisk filesystem blocksize */
#define AKAI_HD_BLOCKSIZE 0x2000 /* 8KB */
/* S900 harddisk */
#define AKAI_HD9_MAXSIZE 0x1fff /* max. harddisk size in harddisk blocks (approx. 64MB) */
#define AKAI_HD9_DEFSIZE 0x09c4 /* default harddisk size in harddisk blocks (approx. 19.5MB) */
#define AKAI_HD9_SH205SIZE 0x0a29 /* "Atari SH205" harddisk size in harddisk blocks (approx. 20.3MB) */
#define AKAI_HD9_SUPRA20MSIZE 0x09c4 /* "Supra 20M" harddisk size in harddisk blocks (approx. 19.5MB) */
#define AKAI_HD9_SUPRA30MSIZE 0x0ee4 /* "Supra 30M" harddisk size in harddisk blocks (approx. 29.8MB) */
#define AKAI_HD9_SUPRA60MSIZE 0x1dc8 /* "Supra 60M" harddisk size in harddisk blocks (approx. 59.6MB) */
/* S1000/S3000 harddisk */
#define AKAI_HD_MAXSIZE 0xffff /* max. harddisk size in harddisk blocks (approx. 512MB, Note: for 16bit block numbers) */
/* S1000/S3000 harddisk sampler partition */
#define AKAI_PART_MAXSIZE 0x1e00 /* max. sampler partition size in harddisk blocks (60MB) */
#define AKAI_PART_NUM 18 /* max. number of sampler partitions per harddisk */
/* S1100/S3000 harddisk DD partition */
/* Note: max. DD partition size in harddisk blocks is AKAI_HD_MAXSIZE */
#define AKAI_DDPART_CBLKS 0x20 /* number of blocks per DD partition cluster */
#define AKAI_DDPART_NUM 18 /* max. number of DD partitions per harddisk */
/* max. disk size in bytes, Note: fits into 32bit */
#define AKAI_DISKSIZE_MAX (AKAI_HD_MAXSIZE*AKAI_HD_BLOCKSIZE)
/* names */
#define AKAI_NAME_LEN_S900 10 /* for S900 */
#define AKAI_NAME_LEN 12 /* for S1000/S3000 */
/* FAT (for floppies and harddisk sampler partitions) */
#define AKAI_FAT_CODE_FREE 0x0000 /* free block */
#define AKAI_FAT_CODE_BAD 0x2000 /* bad block */
#define AKAI_FAT_CODE_SYS900FL 0x0000 /* block reserved for system (S900 floppy), warning: same as for free block!!! */
#define AKAI_FAT_CODE_SYS900HD 0xffff /* block reserved for system (S900 harddisk) */
#define AKAI_FAT_CODE_SYS 0x4000 /* block reserved for system (S1000/S3000) */
#define AKAI_FAT_CODE_DIREND900HD 0x8000 /* end of chain for volume directory (S900 harddisk) */
#define AKAI_FAT_CODE_DIREND1000HD 0x4000 /* end of chain for volume directory (S1000 harddisk), warning: same as for system block!!! */
#define AKAI_FAT_CODE_DIREND3000 0x8000 /* end of chain for volume directory (S3000) */
#define AKAI_FAT_CODE_FILEEND900 0x8000 /* end of chain for file (S900) */
#define AKAI_FAT_CODE_FILEEND 0xc000 /* end of chain for file (S1000/S3000) */
/* DD FAT (for S1100/S3000 harddisk DD partition) */
#define AKAI_DDFAT_CODE_FREE 0x0000 /* free cluster */
#define AKAI_DDFAT_CODE_BAD 0x2000 /* bad cluster */
#define AKAI_DDFAT_CODE_SYS 0x8000 /* cluster reserved for system (header cluster) */
#define AKAI_DDFAT_CODE_END 0xffff /* end of chain */
/* OS versions for volumes and files */
#define AKAI_OSVER_S900VOL 0x0000 /* OS version of S900/S950 volume (zero) */
#define AKAI_OSVER_S1000MAX 0x0428 /* max. OS version of S1000 ("4.40") */
#define AKAI_OSVER_S1100MAX 0x091e /* max. OS version of S1100 ("9.30") */
#define AKAI_OSVER_S3000MAX 0x1100 /* max. OS version of S3000 ("17.00") */
/* file */
#define AKAI_FILE_SIZEMAX 0xffffff /* max. file size in bytes (approx. 16MB, Note: for 24bit size in volume directory entry for file) */
/* entry in volume directory for file */
struct akai_voldir_entry_s{
/* Note: S900 uses first AKAI_NAME_LEN900 chars in name, rest is zero */
u_char name[AKAI_NAME_LEN]; /* file name */
#define AKAI_FILE_TAGNUM 0x04 /* number of tags in volume directory entry for file */
#define AKAI_FILE_TAGFREE 0x00 /* invalid tag number, means: free tag entry for S3000 */
#define AKAI_FILE_TAGS1000 0x20 /* invalid tag number, default for S1000 */
/* Note: valid tag numbers are 1, ..., AKAI_PARTHEAD_TAGNUM */
/* Note: S900 has no tags, all zero */
u_char tag[AKAI_FILE_TAGNUM]; /* tags */
#define AKAI_FTYPE_FREE 0x00 /* invalid file type, means: free entry in volume directory */
u_char type; /* file type */
u_char size[3]; /* file size in bytes (Note: 24bit) */
u_char start[2]; /* start block within partition */
u_char osver[2]; /* if S1000/S3000: OS version */
/* if S900 compressed file: number of un-compressed floppy blocks */
/* else: zero */
}; /* Note: should be 0x0018 Bytes */
/* volume parameters */
/* Note: S900 has no volume parameters */
struct akai_volparam_s{
u_char progselmidich1; /* program select MIDI channel-1 */
u_char progselomni; /* MIDI OMNI for program select */
u_char progselenab; /* program select enable */
u_char prognr1; /* selected program number-1 */
u_char playinominovrr; /* MIDI OMNI override for play input */
u_char sysexch1; /* MIDI system exclusive channel-1 */
u_char dummy1[42]; /* XXX */
}; /* Note: should be 0x0030 Bytes */
/* harddisk volumes */
/* harddisk volume directory of files */
#define AKAI_VOLDIR_ENTRIES_S900HD 128 /* total number of volume directory entries for S900 */
#define AKAI_VOLDIR_ENTRIES_S1000HD 126 /* total number of volume directory entries for S1000 */
#define AKAI_VOLDIR_ENTRIES_S3000HD 510 /* total number of volume directory entries for S3000 */
#define AKAI_VOLDIR_ENTRIES_1BLKHD 341 /* max. number of volume directory entries in 1 harddisk block */
/* S900 harddisk volume */
struct akai_voldir900hd_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S900HD]; /* volume directory entries for files */
u_char dummy1[0x1400]; /* XXX */
}; /* Note: should be 1 harddisk block */
#define AKAI_VOLDIR900HD_BLKS 1
/* S1000 harddisk volume */
struct akai_voldir1000hd_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S1000HD]; /* volume directory entries for files */
struct akai_volparam_s param; /* volume parameters */
u_char dummy1[0x1400]; /* XXX */
}; /* Note: should be 1 harddisk block */
#define AKAI_VOLDIR1000HD_BLKS 1
/* S3000 harddisk volume */
struct akai_voldir3000hd_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S3000HD]; /* volume directory entries for files */
struct akai_volparam_s param; /* volume parameters */
u_char dummy1[0x1000]; /* XXX */
}; /* Note: should be 2 harddisk blocks */
#define AKAI_VOLDIR3000HD_BLKS 2
/* floppy volumes */
/* floppy volume directory of files */
#define AKAI_VOLDIR_ENTRIES_S1000FL 64 /* number of volume directory entries total for S900 and S1000 floppy */
#define AKAI_VOLDIR_ENTRIES_S3000FL 510 /* number of volume directory entries total for S3000 floppy */
/* floppy volume label */
/* Note: S900 has no floppy volume label, all zero */
struct akai_flvol_label_s{
u_char name[AKAI_NAME_LEN]; /* volume name */
u_char dummy1[2]; /* XXX */
u_char osver[2]; /* OS version */
struct akai_volparam_s param; /* volume parameters */
}; /* Note: should be 0x0040 Bytes */
/* low-density floppy header */
/* Note: S900 and S1000 floppy volume directory is within floppy header */
struct akai_fllhead_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S1000FL]; /* volume directory entries for files */
#define AKAI_FAT_ENTRIES_FLL AKAI_FLL_SIZE /* number of FAT entries */
u_char fatblk[AKAI_FAT_ENTRIES_FLL][2]; /* FAT entries for floppy blocks: next block or special code */
/* Note: S900 has no floppy volume label, all zero */
struct akai_flvol_label_s label; /* label */
u_char dummy1[0x0380]; /* XXX */
}; /* Note: should be 4 floppy blocks */
#define AKAI_FLLHEAD_BLKS 4
/* high-density floppy header */
/* Note: S900 and S1000 floppy volume directory is within floppy header */
/* Note: low- and high-density floppy headers are identical */
/* up to first AKAI_FAT_ENTRIES_FLL FAT-entries */
struct akai_flhhead_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S1000FL]; /* volume directory entries for files */
#define AKAI_FAT_ENTRIES_FLH AKAI_FLH_SIZE /* number of FAT entries */
u_char fatblk[AKAI_FAT_ENTRIES_FLH][2]; /* FAT entries for floppy blocks: next block or special code */
/* Note: S900 has no floppy volume label, all zero */
struct akai_flvol_label_s label; /* label */
u_char dummy1[0x0140]; /* XXX */
}; /* Note: should be 5 floppy blocks */
#define AKAI_FLHHEAD_BLKS 5
/* S3000 floppy volume directory (behind header) */
struct akai_voldir3000fl_s{
struct akai_voldir_entry_s file[AKAI_VOLDIR_ENTRIES_S3000FL]; /* volume directory entries for files */
u_char dummy1[0x0030]; /* Note: volume parameters are in floppy header */
}; /* Note: should be 12 floppy blocks */
#define AKAI_VOLDIR3000FL_BLKS 12
#define AKAI_VOLDIR3000FLL_BSTART 4 /* start block for low-density */
#define AKAI_VOLDIR3000FLH_BSTART 5 /* start block for high-density */
/* flag for S3000 floppy: invalid type of first file in floppy header */
#define AKAI_VOLDIR3000FL_FTYPE 0xff /* invalid file type, used as flag for S3000 floppy volume */
/* generic volume */
/* Note: first file starts at byte 0 in first block */
union akai_voldir_u{
struct akai_voldir900hd_s s900hd;
struct akai_voldir1000hd_s s1000hd;
struct akai_voldir3000hd_s s3000hd;
/* Note: S900 and S1000 floppy volume is within floppy header */
struct akai_voldir3000fl_s s3000fl;
};
/* entry in root directory for volume on S900 harddisk */
struct akai_hd9rootdir_entry_s{
u_char name[AKAI_NAME_LEN_S900]; /* volume name */
#define AKAI_VOL_START_INACT 0x0000 /* inactive */
u_char start[2]; /* start block on harddisk */
}; /* Note: should be 0x000c Bytes */
/* S900 harddisk header */
struct akai_hd9head_s{
#define AKAI_HD9ROOTDIR_ENTRIES 128 /* number of root directory entries for volumes */
struct akai_hd9rootdir_entry_s vol[AKAI_HD9ROOTDIR_ENTRIES]; /* root directory for volumes */
u_char size[2]; /* harddisk size in harddisk blocks */
#define AKAI_HD9FLAG1_SIZEVALID 0xff /* if size[] is valid */
u_char flag1; /* XXX */
u_char flag2; /* XXX */
#define AKAI_HD9FAT0_ENTRIES 0x0cfe /* number of copied FAT entries */
u_char fatblk0[AKAI_HD9FAT0_ENTRIES][2]; /* copy of first FAT entries */
#define AKAI_HD9FAT_ENTRIES AKAI_HD9_MAXSIZE /* max. number of FAT entries */
u_char fatblk[AKAI_HD9FAT_ENTRIES][2]; /* FAT entries for harddisk blocks: next block or special code */
u_char dummy1[0x6000-AKAI_HD9FAT_ENTRIES*2]; /* XXX */
}; /* Note: should be 4 harddisk blocks */
#define AKAI_HD9HEAD_BLKS 4
/* entry in root directory for volume in S1000/S3000 harddisk sampler partition */
struct akai_rootdir_entry_s{
u_char name[AKAI_NAME_LEN]; /* volume name */
#define AKAI_VOL_TYPE_INACT 0x00 /* inactive */
#define AKAI_VOL_TYPE_S1000 0x01 /* S1000 */
#define AKAI_VOL_TYPE_S3000 0x03 /* S3000 or CD3000 */
#define AKAI_VOL_TYPE_CD3000 0x07 /* CD3000 CD-ROM (compatible with AKAI_VOL_TYPE_S3000) */
u_char type; /* volume type */
#define AKAI_VOL_LNUM_OFF 0
#define AKAI_VOL_LNUM_MIN 1
#define AKAI_VOL_LNUM_MAX 128
u_char lnum; /* load number */
u_char start[2]; /* start block within partition */
}; /* Note: should be 0x0010 Bytes */
/* S1000/S3000 harddisk sampler and DD partition table (only in first sampler partition) */
struct akai_parttab_s{
#define AKAI_PARTTAB_MAGICNUM 128 /* number of fields */
#define AKAI_PARTTAB_MAGICVAL 9999 /* magic base value */
u_char magic[AKAI_PARTTAB_MAGICNUM][2]; /* magic fields, indicate S1000/S3000 harddisk partition table, only in first sampler partition */
u_char partnum; /* number of sampler partitions, only in first sampler partition */
u_char ddpartnum; /* number of DD partitions */
u_char part[AKAI_PART_NUM+1][2]; /* sampler partition table, only in first sampler partition */
u_char ddpart[AKAI_DDPART_NUM+1][2]; /* DD partition table, only in first sampler partition */
u_char dummy1[0x0100-2-2*(AKAI_PART_NUM+1)-2*(AKAI_DDPART_NUM+1)]; /* XXX */
}; /* Note: should be 0x0202 Bytes */
/* S1000/S3000 harddisk sampler partition header */
struct akai_parthead_s{
u_char size[2]; /* partition size in harddisk blocks */
#define AKAI_PARTHEAD_MAGICNUM 98 /* number of fields */
#define AKAI_PARTHEAD_MAGICVAL 3333 /* magic base value */
u_char magic[AKAI_PARTHEAD_MAGICNUM][2]; /* magic fields, indicate S1000/S3000 harddisk sampler partition */
u_char chksum[4]; /* checksum of all above */
#define AKAI_ROOTDIR_ENTRIES 100 /* number of root directory entries for volumes */
struct akai_rootdir_entry_s vol[AKAI_ROOTDIR_ENTRIES]; /* root directory for volumes */
#define AKAI_FAT_ENTRIES AKAI_PART_MAXSIZE /* max. number of FAT entries */
u_char fatblk[AKAI_FAT_ENTRIES][2]; /* FAT entries for sampler partition blocks: next block or special code */
u_char dummy1[0x00f6]; /* XXX */
struct akai_parttab_s parttab; /* partition table, only in first sampler partition */
#define AKAI_PARTHEAD_TAGSMAGIC "TAGS" /* magic for tags */
u_char tagsmagic[4]; /* magic for tags */
#define AKAI_PARTHEAD_TAGNUM 26 /* number of tags */
u_char tag[AKAI_PARTHEAD_TAGNUM][AKAI_NAME_LEN]; /* tag names */
u_char dummy2[0x1a00-4-AKAI_PARTHEAD_TAGNUM*AKAI_NAME_LEN]; /* XXX */
}; /* Note: should be 3 harddisk blocks */
#define AKAI_PARTHEAD_BLKS 3
/* S1100/S3000 DD take header (directory entry in DD partition header) */
/* XXX should be defined in akaiutil_take.h, but must be in akaiutil.h due to dependencies */
struct akai_ddtake_s{
u_char name[AKAI_NAME_LEN]; /* name */
u_char cstarts[2]; /* start cluster for sample */
u_char cstarte[2]; /* start cluster for envelope */
u_char wstart[4]; /* sample start word (16bit) */
u_char wend[4]; /* sample end word (16bit) */
#define AKAI_DDTAKESTAT_FREE 0x00 /* free directory entry */
#define AKAI_DDTAKESTAT_USED 0x01 /* used directory entry */
u_char stat; /* directory entry status */
#define AKAI_DDTAKESTYPE_MONO 0x00 /* sample type mono */
#define AKAI_DDTAKESTYPE_STEREO 0x01 /* sample type stereo */
u_char stype; /* sample type */
u_char srate[2]; /* sample rate in Hz */
u_char vspeed[2]; /* varispeed (signed) */
u_char finerate[2]; /* fine rate (signed) */
u_char wstartm[4]; /* edit marker sample start word (16bit) */
u_char wendm[4]; /* edit marker sample end word (16bit) */
u_char fadein[2]; /* fade in time in ms */
u_char fadeout[2]; /* fade out time in ms */
u_char stlvl; /* stereo output level */
u_char pan; /* panning (signed) */
u_char stmix; /* stereo mix (ON=0x01, OFF=0x00) */
u_char midich1; /* MIDI channel-1 */
u_char midinote; /* MIDI note */
u_char startm; /* start mode */
u_char deemph; /* de-emphasis (ON=0x01, OFF=0x00) */
u_char dummy1[5]; /* XXX */
u_char predel[2]; /* pre-delay time in ms */
u_char outlvl; /* output level */
u_char outch; /* output channel pair */
u_char fxbus; /* FX bus */
u_char sendlvl; /* send level */
u_char dummy2[2]; /* XXX */
}; /* Note: should be 0x0040 Bytes */
/* S1100/S3000 harddisk DD partition header */
struct akai_ddparthead_s{
#define AKAI_DDFAT_ENTRIES 0x07ff /* max. number of DD FAT entries (AKAI_HD_MAXSIZE/AKAI_DDPART_CBLKS) */
u_char fatcl[AKAI_DDFAT_ENTRIES][2]; /* FAT entries for DD partition clusters: next cluster or special code */
u_char dummy1[0x2000-AKAI_DDFAT_ENTRIES*2]; /* XXX */
#define AKAI_DDTAKE_MAXNUM 256 /* max. number of DD takes */
struct akai_ddtake_s take[AKAI_DDTAKE_MAXNUM]; /* directory of DD takes */
}; /* Note: should be 3 harddisk blocks (rest of cluster is junk) */
#define AKAI_DDPARTHEAD_BLKS 3
#define AKAI_DDTAKE_ENVBLKSIZW 128 /* envelope block size in words */
#define AKAI_DDTAKE_ENVMAXVAL 0x20 /* max. envelope value */
/* generic header */
union akai_head_u{
struct akai_fllhead_s fll; /* low-density floppy header */
struct akai_flhhead_s flh; /* high-density floppy header */
struct akai_hd9head_s hd9; /* S900 harddisk header */
struct akai_parthead_s hd; /* S1000/S3000 harddisk sampler partition header */
struct akai_ddparthead_s dd; /* S1000/S3000 harddisk DD partition header */
};
/* Note: see comment above: */
/* may access files and first blocks in FAT via */
/* high-density floppy header also for low-density floppy case */
/* CD-ROM info header in S1000/S3000 sampler partition */
struct akai_cdinfohead_s{
u_char fnum[2]; /* number of files */
u_char volesiz[AKAI_ROOTDIR_ENTRIES][2]; /* size of volume directory entries for files in bytes */
u_char cdlabel[AKAI_NAME_LEN]; /* CD-ROM label */
}; /* Note: should be 0x00d6 Bytes */
/* Note: followed by voldir entries of files */
#define AKAI_CDINFO_BLK AKAI_PARTHEAD_BLKS /* start block (following sampler partition header) */
#define AKAI_CDINFO_MINSIZB 3 /* min. size in harddisk blocks */
#define AKAI_CDINFO_DEFLABEL "CDROM" /* XXX default label */
/* private data structures */
/* disk */
struct disk_s{
u_int index; /* disk index */
int fd; /* disk file descriptor */
#ifdef _VISUALCPP
int fldrn; /* floppy drive number (or -1 if none) */
#endif /* _VISUALCPP */
int readonly; /* read-only flag */
OFF64_T startoff; /* start offset in bytes */
u_int totsize; /* size in bytes */
#define DISK_TYPE_FLL 1 /* low-density floppy */
#define DISK_TYPE_FLH 2 /* high-density floppy */
#define DISK_TYPE_HD9 9 /* S900 harddisk */
#define DISK_TYPE_HD 3 /* S1000/S3000 harddisk */
u_int type; /* disk type */
u_int blksize; /* blocksize in bytes */
u_int bsize; /* size in blocks */
};
/* partition */
struct part_s{
struct disk_s *diskp; /* pointer to disk */
int valid; /* check passed */
#define PART_TYPE_FLL DISK_TYPE_FLL /* low-density floppy */
#define PART_TYPE_FLH DISK_TYPE_FLH /* high-density floppy */
#define PART_TYPE_HD9 DISK_TYPE_HD9 /* S900 harddisk */
#define PART_TYPE_HD DISK_TYPE_HD /* S1000/S3000 harddisk sampler partition */
#define PART_TYPE_DD 4 /* S1100/S3000 harddisk DD partition (at end of harddisk) */
u_int type; /* partition type */
u_int index; /* index on disk */
u_int blksize; /* blocksize in bytes */
u_int bstart; /* start block on disk */
u_int bsize; /* size in blocks */
u_int csize; /* if DD partition: size in clusters */
u_int bsyssize; /* if not DD partition: reserved blocks for system (partition header or floppy header) */
u_int bfree; /* free blocks */
u_int bbad; /* bad blocks */
u_char (*fat)[2]; /* start of FAT */
union akai_head_u head; /* whole header */
u_int volnummax; /* if not DD partition: max. number of volumes */
char letter; /* letter (ASCII) */
};
/* Note: fat points into original part_s head => must not use(!) a copy of a part_s !!! */
/* volume */
struct vol_s{
struct part_s *partp; /* pointer to partition */
u_int index; /* index in root directory */
#define AKAI_VOL_TYPE_S900 0xf9 /* fake type for S900, not valid for type in S1000/S3000 root directory */
u_int type; /* volume type */
u_int lnum; /* load number */
u_int osver; /* OS version */
#define VOL_DIRBLKS AKAI_VOLDIR3000FL_BLKS /* XXX max. number of volume blocks */
u_int dirblk[VOL_DIRBLKS]; /* directory blocks */
u_int fimax; /* max. file entries */
struct akai_voldir_entry_s *file; /* pointer to start of files */
struct akai_volparam_s *param; /* pointer to volume parameters */
union akai_voldir_u dir; /* whole volume directory (except for S900 and S1000 floppy) */
char name[AKAI_NAME_LEN+1]; /* name (ASCII), +1 for '\0' */
};
/* Note: file, param point into original vol_s dir => must not use(!) a copy of a vol_s !!! */
/* => use akai_copy_vol() to obtain a self-contained copy of a vol_s */
/* Note: must be careful with partp if part_s behind it has changed/disappeared !!! */
/* this should never be a problem since system-wide unique and static part[] */
/* sampler file */
struct file_s{
struct vol_s *volp; /* pointer to volume */
u_int index; /* index in volume directory */
u_int bstart; /* start block */
u_int size; /* size in bytes */
u_int type; /* type */
u_int osver; /* OS version */
u_char tag[AKAI_FILE_TAGNUM]; /* tags */
char name[AKAI_NAME_LEN+4+1]; /* name (ASCII), +4 for ".<type>", +1 for '\0' */
};
/* Note: must be careful with volp if vol_s behind it has changed/disappeared !!! */
/* this could be a problem with non-unique curvolp/curvol_buf */
/* disks */
#ifndef DISK_NUM_MAX
#define DISK_NUM_MAX 64 /* XXX */
#endif
extern struct disk_s disk[DISK_NUM_MAX]; /* disks, Note: one for each disk, system-wide */
extern u_int disk_num; /* number of disks */
/* partitions */
#ifndef PART_NUM_MAX
#define PART_NUM_MAX 512 /* XXX */
#endif
extern struct part_s part[PART_NUM_MAX]; /* partitions, Note: one for each partition, system-wide */
extern u_int part_num; /* number of partitions */
/* current directory */
extern struct disk_s *curdiskp; /* current disk pointer into disk[], NULL if system-level */
/* Note: unique, fixed mapping to each file */
extern struct part_s *curpartp; /* current partition pointer into part[], NULL if disk-level */
/* Note: unique, fixed mapping to each partition */
extern struct vol_s *curvolp; /* current volume pointer into curvol_buf, NULL if disk- or partition-level */
/* Note: neither fixed nor unique mapping to each volume!!! */
extern struct vol_s curvol_buf; /* current volume buffer, Note: only one buffer, might change volume identity!!! */
/* for operations with current directory, Note: one instance only, not recursive!!! */
extern int savecurfd;
extern struct part_s *savecurpartp;
extern struct vol_s *savecurvolp;
extern struct vol_s savecurvol_buf;
extern int savecurvolmodflag; /* modifier flag */
extern char savecurvolname[AKAI_NAME_LEN+1]; /* +1 for '\0' */
/* Note: dirnamebuf[] must be large enough to contain path of max. possible size */
#define DIRNAMEBUF_LEN 256 /* XXX */
extern char dirnamebuf[DIRNAMEBUF_LEN+1]; /* +1 for '\0' */
extern u_char curfiltertag[AKAI_FILE_TAGNUM];
/* Declarations */
#ifndef PSEUDODISK_NUM_MAX
#define PSEUDODISK_NUM_MAX 8 /* XXX max. number of pseudo-disks per file descriptor */
#endif
extern int open_disk(char *name,int readonly,OFF64_T startoff,u_int pseudodisksize,u_int pseudodisknum);
extern void close_alldisks(void);
#ifndef AKAI_DISKSIZE_GRAN
#define AKAI_DISKSIZE_GRAN 2048 /* XXX disk size granularity in bytes, compatible with CD-ROM */
#endif
extern u_int akai_disksize(int fd,OFF64_T startoff,u_int disksizemax);
extern int akai_io_blks(struct part_s *pp,u_char *buf,u_int bstart,u_int bsize,int cachealloc,int mode);
extern int akai_openreadonly_extfile(char *name);
extern int akai_check_extwavname(char *wavname);
extern void akai_countfree_part(struct part_s *pp);
extern int akai_check_fatblk(u_int blk,u_int bsize,u_int bsyssize);
extern int print_fatchain(struct part_s *pp,u_int blk);
extern int akai_free_fatchain(struct part_s *pp,u_int bstart,int writeflag);
extern int akai_allocate_fatchain(struct part_s *pp,u_int bsize,u_int *bstartp,u_int bcont0,u_int endcode);
extern int akai_scanbad(struct part_s *pp,int markflag);
extern int akai_read_file(int outfd,u_char *outbuf,struct file_s *fp,u_int begin,u_int end);
extern int akai_write_file(int inpfd,u_char *inpbuf,struct file_s *fp,u_int begin,u_int end);
extern int print_ddfatchain(struct part_s *pp,u_int cstart);
extern u_int akai_count_ddfatchain(struct part_s *pp,u_int cstart);
extern int akai_free_ddfatchain(struct part_s *pp,u_int cstart,int writeflag);
extern int akai_allocate_ddfatchain(struct part_s *pp,u_int csize,u_int *cstartp,u_int ccont0);
extern int akai_export_ddfatchain(struct part_s *pp,u_int cstart,u_int bstart,u_int bsize,int outfd,u_char *outbuf);
extern int akai_import_ddfatchain(struct part_s *pp,u_int cstart,u_int bstart,u_int bsize,int inpfd,u_char *inpbuf);
extern char akai2ascii(u_char c);
extern char akai2ascii900(u_char c);
extern void akai2ascii_name(u_char *aname,char *name,int s900flag);
extern void akai2ascii_filename(u_char *aname,u_char ft,u_int osver,char *name,int s900flag);
extern u_char ascii2akai(char a);
extern u_char ascii2akai900(char a);
extern void ascii2akai_name(char *name,u_char *aname,int s900flag);
extern u_char ascii2akai_filename(char *name,u_char *aname,u_int *osverp,int s900flag);
extern void akai_vol_info(struct vol_s *vp,u_int ai,int verbose);
extern void akai_list_vol(struct vol_s *vp,u_char *filtertagp);
extern int akai_read_voldir(struct vol_s *vp);
extern int akai_write_voldir(struct vol_s *vp,u_int fi);
extern void akai_copy_structvol(struct vol_s *srcvp,struct vol_s *dstvp);
extern int akai_get_vol(struct part_s *pp,struct vol_s *vp,u_int vi);
extern int akai_find_vol(struct part_s *pp,struct vol_s *vp,char *name);
extern int akai_rename_vol(struct vol_s *vp,char *name,u_int lnum,u_int osver,struct akai_volparam_s *parp);
#define AKAI_CREATE_VOL_NOINDEX ((u_int)-1) /* no user-supplied index */
extern int akai_create_vol(struct part_s *pp,struct vol_s *vp,u_int type,u_int index,char *name,u_int lnum,struct akai_volparam_s *parp);
extern int akai_wipe_vol(struct vol_s *vp,int delflag);
extern void akai_list_volparam(struct akai_volparam_s *parp,int listflag);
extern void akai_init_volparam(struct akai_volparam_s *parp,int s3000flag);
extern void akai_print_lnum(u_int lnum);
extern u_int akai_get_lnum(char *name);
extern int copy_tags(struct part_s *srcpp,struct part_s *dstpp);
extern void akai_list_tags(struct part_s *pp);
extern int akai_rename_tag(struct part_s *pp,char *name,u_int ti,int wipeflag);
extern void akai_print_cdinfo(struct part_s *pp,int verbose);
extern int akai_set_cdinfo(struct part_s *pp,char *cdlabel);
extern void akai_part_info(struct part_s *pp,int verbose);
extern void akai_list_part(struct part_s *pp,int recflag,u_char *filtertagp);
extern struct part_s *akai_find_part(struct disk_s *dp,char *name);
extern void print_fat(struct part_s *pp);
extern void akai_disk_info(struct disk_s *dp,int verbose);
extern void akai_list_disk(struct disk_s *dp,int recflag,u_char *filtertagp);
extern void akai_list_alldisks(int recflag,u_char *filtertagp);
extern void akai_sort_filetags(u_char *tagp);
extern int akai_set_filetag(u_char *tagp,u_int ti);
extern int akai_clear_filetag(u_char *tagp,u_int ti);
extern int akai_match_filetags(u_char *filtertagp,u_char *testtagp);
extern int akai_get_file(struct vol_s *vp,struct file_s *fp,u_int fi);
extern int akai_find_file(struct vol_s *vp,struct file_s *fp,char *name);
extern int akai_rename_file(struct file_s *fp,char *name,struct vol_s *vp,u_int dstindex,u_char *tagp,u_int osver);
#define AKAI_CREATE_FILE_NOINDEX ((u_int)-1) /* no user-supplied index */
extern int akai_create_file(struct vol_s *vp,struct file_s *fp,u_int size,u_int index,char *name,u_int osver,u_char *tagp);
extern void akai_fvol1000_initfile(struct akai_voldir_entry_s *ep,u_int osver,u_int tag);
extern int akai_delete_file(struct file_s *fp);
extern int akai_rename_ddtake(struct part_s *pp,u_int ti,char *name);
extern int akai_delete_ddtake(struct part_s *pp,u_int ti);
extern void akai_fix_partheadmagic(struct part_s *pp);
extern int akai_check_partheadmagic(struct part_s *pp);
extern void akai_fix_parttabmagic(struct akai_parttab_s *ptp);
extern int akai_check_parttabmagic(struct akai_parttab_s *ptp);
extern int akai_scan_floppy(struct disk_s *dp);
extern int akai_scan_harddisk9(struct disk_s *dp);
extern int akai_scan_ddpart(struct disk_s *dp,struct akai_parttab_s *ptp,u_int bstart,u_int pi);
extern int akai_scan_disk(struct disk_s *dp,int floppyenable);
extern int akai_wipe_part(struct part_s *pp,int wipeflag,struct part_s *plistp,u_int pimax,int cdromflag);
extern int akai_wipe_harddisk(struct disk_s *dp,u_int bsize,u_int totb,int s3000flag,int cdromflag);
extern int akai_wipe_harddisk9(struct disk_s *dp,u_int totb);
extern int akai_wipe_floppy(struct disk_s *dp,int lodensflag,int s3000flag,int s900flag);
extern int change_curdir(char *name,u_int vi,char *lastname,int checklast);
extern int change_curdir_home(void);
extern void save_curdir(int modflag);
extern void restore_curdir(void);
extern void curdir_info(int verbose,char *pathbuf);
extern void list_curdir(int recflag);
extern void list_curfiltertags(void);
extern int copy_file(struct file_s *srcfp,struct vol_s *dstvp,struct file_s *dstfp,u_int dstindex,char *dstname,int delflag);
extern int copy_vol_allfiles(struct vol_s *srcvp,struct part_s *dstpp,char *dstname,int delflag,int verbose);
extern int copy_part_allvols(struct part_s *srcpp,struct part_s *dstpp,int delflag,int verbose);
extern int check_curnosamplervol(void);
extern int check_curnosamplerpart(void);
extern int check_curnoddpart(void);
extern int check_curnopart(void);
#endif /* !__AKAIUTIL_H */
+20
View File
@@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "akaiutil", "akaiutil.vcproj", "{3F010352-C096-4963-887A-7C23C83616DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3F010352-C096-4963-887A-7C23C83616DF}.Debug|Win32.ActiveCfg = Debug|Win32
{3F010352-C096-4963-887A-7C23C83616DF}.Debug|Win32.Build.0 = Debug|Win32
{3F010352-C096-4963-887A-7C23C83616DF}.Release|Win32.ActiveCfg = Release|Win32
{3F010352-C096-4963-887A-7C23C83616DF}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+259
View File
@@ -0,0 +1,259 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="akaiutil"
ProjectGUID="{3F010352-C096-4963-887A-7C23C83616DF}"
RootNamespace="akaiutil"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_VISUALCPP;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;DEBUG"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Winmm.lib"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;_VISUALCPP;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Winmm.lib"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Quelldateien"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\akaiutil.c"
>
</File>
<File
RelativePath=".\akaiutil_file.c"
>
</File>
<File
RelativePath=".\akaiutil_io.c"
>
</File>
<File
RelativePath=".\akaiutil_main.c"
>
</File>
<File
RelativePath=".\akaiutil_take.c"
>
</File>
<File
RelativePath=".\akaiutil_tar.c"
>
</File>
<File
RelativePath=".\akaiutil_wav.c"
>
</File>
<File
RelativePath=".\commonlib.c"
>
</File>
</Filter>
<Filter
Name="Headerdateien"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\akaiutil.h"
>
</File>
<File
RelativePath=".\akaiutil_file.h"
>
</File>
<File
RelativePath=".\akaiutil_io.h"
>
</File>
<File
RelativePath=".\akaiutil_take.h"
>
</File>
<File
RelativePath=".\akaiutil_tar.h"
>
</File>
<File
RelativePath=".\akaiutil_wav.h"
>
</File>
<File
RelativePath=".\commoninclude.h"
>
</File>
<File
RelativePath=".\fdrawcmd.h"
>
</File>
</Filter>
<Filter
Name="Ressourcendateien"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+2940
View File
File diff suppressed because it is too large Load Diff
+563
View File
@@ -0,0 +1,563 @@
#ifndef __AKAIUTIL_FILE_H
#define __AKAIUTIL_FILE_H
/*
* Copyright (C) 2010,2012,2018,2019,2020 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#include "akaiutil.h"
/* AKAI files */
/* Note: all data types are little endian */
/* AKAI file type ranges */
#define AKAI_S900_FTYPE_MIN 'A' /* min. file type for S900 */
#define AKAI_S900_FTYPE_MAX 'Z' /* max. file type for S900 */
#define AKAI_S1000_FTYPE_MIN 'a' /* min. file type for S1000 */
#define AKAI_S1000_FTYPE_MAX 'z' /* max. file type for S1000 */
#define AKAI_S3000_FTYPE_MIN ('a'+0x80) /* min. file type for S3000 */
#define AKAI_S3000_FTYPE_MAX ('z'+0x80) /* max. file type for S3000 */
/* Note: exception: AKAI_CDSETUP3000_FTYPE=='T' is within range of file types for S900 */
/* AKAI S900 sample header */
struct akai_sample900_s{
char name[AKAI_NAME_LEN_S900]; /* sample name (in RAM) */
u_char dummy1[6]; /* XXX 0x00 */
u_char slen[4]; /* number of samples */
u_char srate[2]; /* sample rate in Hz */
#define SAMPLE900_NPITCH_DEF (60*16) /* default */
u_char npitch[2]; /* nominal pitch in 1/16 semitones */
u_char loud[2]; /* loudness offset (signed) */
#define SAMPLE900_PMODE_ONESHOT 'O'
#define SAMPLE900_PMODE_LOOP 'L'
#define SAMPLE900_PMODE_ALTLOOP 'A'
u_char pmode; /* playback mode */
u_char dummy2; /* XXX */
u_char end[4]; /* end marker */
u_char start[4]; /* start marker */
u_char llen[4]; /* loop length */
u_char dmadesa[2]; /* address of DMA descriptor list (updated by sampler) */
#define SAMPLE900_TYPE_NORM 0x00 /* normal */
#define SAMPLE900_TYPE_VELXF 0xff /* velocity crossfade */
u_char type; /* sample type */
#define SAMPLE900_DIR_NORM 'N'
#define SAMPLE900_DIR_REV 'R'
u_char dir; /* time direction */
u_char dummy3[10]; /* XXX */
u_char locat[4]; /* absolute address (updated by sampler) */
u_char dummy4[2]; /* XXX */
}; /* Note: should be 0x003c Bytes */
/* Note: header is followed by sample data (in non-compressed or compressed sample format) */
/* S900 compressed sample format */
#define SAMPLE900COMPR_GROUP_SAMPNUM 10 /* number of samples per group */
#define SAMPLE900COMPR_UPBITNUM_NEGCODE_OFF 16 /* offset between bit number for upabsval and -code */
#define SAMPLE900COMPR_UPBITNUM_MAX 12 /* max. bit number to be used for upabsval */
#define SAMPLE900COMPR_INTERVALSIZ (1<<SAMPLE900COMPR_UPBITNUM_MAX) /* interval size for max. bit number */
#define SAMPLE900COMPR_BITMASK (SAMPLE900COMPR_INTERVALSIZ-1) /* bit mask for interval */
#define SAMPLE900COMPR_INTERVALSIZ2 (SAMPLE900COMPR_INTERVALSIZ>>1) /* half interval size */
#define AKAI_SAMPLE900_FTYPE 'S' /* file type */
/* AKAI S900 program header */
struct akai_program900_s{
char name[AKAI_NAME_LEN_S900]; /* program name (in RAM) */
u_char dummy1[6]; /* XXX 0x00 */
u_char dummy2[2]; /* XXX */
#define PROGRAM900_KGA_NONE 0x0000 /* value for none */
u_char kg1a[2]; /* address of keygroup 1 (updated by sampler) */
u_char dummy3; /* XXX */
u_char kgxf; /* keygroup (positional) crossfade enable */
u_char dummy4; /* XXX */
u_char kgnum; /* number of keygroups */
u_char dummy5[14]; /* XXX */
}; /* Note: should be 0x0026 Bytes */
/* Note: header is followed by keygroups */
/* AKAI S900 program: keygroup */
struct akai_program900kg_s{
u_char keyhi; /* high MIDI key */
u_char keylo; /* low MIDI key */
#define PROGRAM900KG_VELSWTH_NOSOFT 0 /* value for no soft sample */
#define PROGRAM900KG_VELSWTH_NOLOUD 128 /* value for no loud sample */
u_char velswth; /* velocity switch threshold */
u_char dummy1[15]; /* XXX */
#define PROGRAM900KG_FLAGS_PCONST 0x01 /* constant pitch enable */
#define PROGRAM900KG_FLAGS_VELXF 0x02 /* velocity crossfade enable */
#define PROGRAM900KG_FLAGS_ONESHOT 0x08 /* one-shot trigger mode enable */
u_char flags; /* flags */
#define PROGRAM900KG_OUTCH1_LEFT 0x08 /* code for LEFT */
#define PROGRAM900KG_OUTCH1_RIGHT 0x09 /* code for RIGHT */
#define PROGRAM900KG_OUTCH1_ANY 0xff /* code for ANY */
u_char outch1; /* audio output channel: channel number-1 or code */
u_char midichoff; /* MIDI channel offset */
u_char dummy2[3]; /* XXX */
u_char sname1[AKAI_NAME_LEN_S900]; /* sample name (in RAM) for sample 1 ("soft") */
u_char dummy3[4]; /* XXX */
u_char velxfv50; /* if velocity crossfade: velocity value for 50% */
u_char dummy4; /* XXX */
#define PROGRAM900KG_SHDRA_NONE 0x0000 /* value for none */
u_char shdra1[2]; /* address of sample header for sample 1 (updated by sampler) */
u_char tune1[2]; /* tuning offset (transpose) in 1/16 semitones (signed) for sample 1 */
u_char filter1; /* filter for sample 1 */
u_char loud1; /* loudness offset (signed) for sample 1 */
u_char sname2[AKAI_NAME_LEN_S900]; /* sample name (in RAM) for sample 2 ("loud") */
u_char dummy5[6]; /* XXX */
u_char shdra2[2]; /* address of sample header for sample 2 (updated by sampler) */
u_char tune2[2]; /* tuning offset in 1/16 semitones (signed) for sample 2 */
u_char filter2; /* filter for sample 2 */
u_char loud2; /* loudness offset (signed) for sample 2 */
u_char kgnexta[2]; /* address of next keygroup (updated by sampler) */
}; /* Note: should be 0x0046 Bytes */
#define AKAI_PROGRAM900_FTYPE 'P' /* file type */
/* AKAI S900/S950 drum settings descriptor */
struct akai_drum900des_s{
u_char inpnr1; /* input number-1 */
u_char midich1; /* MIDI channel-1 */
u_char midinote; /* MIDI note */
u_char gain; /* gain */
u_char ask90_trig; /* if ASK90: trigger threshold */
/* if ME35T: (ignored) */
u_char dummy1[3]; /* XXX */
#define DRUM900DES_ITYPE_ASK90 0x00 /* interface type: ASK90 */
#define DRUM900DES_ITYPE_ME35T 0xff /* interface type: ME35T */
u_char itype; /* interface type */
u_char me35t_trig; /* if ASK90: (ignored) */
/* if ME35T: trigger threshold */
u_char me35t_vcurv1; /* if ASK90: (ignored) */
/* if ME35T: "V-curve"-1 */
u_char dummy2; /* XXX */
u_char captt4[2]; /* 4* capture time in msec */
u_char ontime4[2]; /* 4* on-time in msec */
u_char recovt4[2]; /* 4* recovery time in msec */
u_char dummy3[8];
u_char ask90_resba[2]; /* if ASK90: ASK90 base address for CH RESET */
/* if ME35T: (ignored) */
u_char ask90_adcla[2]; /* if ASK90: ASK90 address for ADC latch */
/* if ME35T: (ignored) */
}; /* Note: should be 0x001e Bytes */
/* AKAI S900/S950 drum settings file */
struct akai_drum900_s{
u_char ask90enab; /* if ASK90: ASK90 enable */
/* if ME35T: (ignored) */
u_char ask90sens; /* if ASK90: ASK90 sensitivity */
/* if ME35T: (ignored) */
u_char dummy1[20]; /* XXX 0x00 ... 0x00 */
#define DRUM900_INPUTNUM 8 /* number of drum trigger inputs */
struct akai_drum900des_s ddes[DRUM900_INPUTNUM]; /* drum setting descriptors */
}; /* Note: should be 0x0106 Bytes */
#define AKAI_DRUM900_FTYPE 'D' /* file type */
#define AKAI_DRUM900_FNAME "DRUM SET " /* default file name */
/* AKAI S900 overall settings file */
struct akai_ovs900_s{
char progname[AKAI_NAME_LEN_S900]; /* selected program name */
u_char dummy1[6]; /* XXX 0x20 ... 0x20 */
u_char dummy2[4]; /* XXX */
u_char testmidich[2]; /* test MIDI channel */
u_char testmidikey[2]; /* test MIDI key */
u_char testmidivel[2]; /* test MIDI velocity */
u_char dummy3; /* XXX */
#define OVS900_BMIDICH1MASK 0x7f /* bit mask for basic MIDI channel-1 */
#define OVS900_OMNIMASK 0x80 /* bit mask for OMNI flag */
u_char bmidich1omni; /* basic MIDI channel-1 | OMNI flag */
u_char loudness; /* loudness enable */
#define OVS900_CTRLPORT_MIDI 0x01 /* control port: MIDI */
#define OVS900_CTRLPORT_RS232 0x02 /* control port: RS232 */
u_char ctrlport; /* control port */
u_char progchange; /* program change enable */
u_char dummy4[4]; /* XXX */
u_char pwheelrange; /* pitch wheel range */
u_char rs232brate10[2]; /* RS232 baudrate/10 */
u_char dummy5[2]; /* XXX */
}; /* Note: should be 0x0028 Bytes */
#define AKAI_OVS900_FTYPE 'O' /* file type */
#define AKAI_OVS900_FNAME "OVERALL SE" /* default file name */
/* AKAI S900 fixup file */
#define AKAI_FIXUP900_FTYPE 'F' /* file type */
/* AKAI S900 memory image file */
#define AKAI_MEMIMG900_FTYPE 'M' /* file type */
/* AKAI S1000 empty file name */
#define AKAI_EMPTY1000_FNAME "VVVVVVVVVVVV" /* S1000 empty file name */
/* AKAI S1000 generic header */
struct akai_genfilehdr_s{
u_char blockid; /* block ID */
u_char dummy1[2]; /* XXX */
u_char name[AKAI_NAME_LEN]; /* file name (in RAM) */
}; /* Note: should be 0x000f Bytes */
/* AKAI S1000 sample loop parameters */
struct akai_sample1000loop_s{
u_char at[4]; /* loop at marker */
u_char flen[2]; /* loop fine length in 1/65536 sample */
u_char len[4]; /* loop length in samples */
#define SAMPLE1000LOOP_TIME_NOLOOP 0 /* value for NOLOOP */
#define SAMPLE1000LOOP_TIME_HOLD 9999 /* value for HOLD */
u_char time[2]; /* loop time in msec */
};
/* AKAI S1000 sample header */
struct akai_sample1000_s{
#define SAMPLE1000_BLOCKID 0x03
u_char blockid; /* block ID */
#define SAMPLE1000_BANDW_10KHZ 0x00
#define SAMPLE1000_BANDW_20KHZ 0x01
u_char bandw; /* bandwidth select */
u_char rkey; /* MIDI root key (typ. 0x3c) */
u_char name[AKAI_NAME_LEN]; /* sample name (in RAM) */
u_char dummy1; /* XXX 0x80 */
u_char lnum; /* number of loops */
u_char lfirst; /* first active loop-1 */
u_char dummy2; /* XXX 0x00 */
#define SAMPLE1000_PMODE_LOOP 0x00
#define SAMPLE1000_PMODE_LOOPNOTREL 0x01
#define SAMPLE1000_PMODE_NOLOOP 0x02
#define SAMPLE1000_PMODE_TOEND 0x03
u_char pmode; /* playback mode */
u_char ctune; /* cents tune (signed) */
u_char stune; /* semitone tune (signed) */
u_char locat[4]; /* absolute address (updated by sampler) */
u_char slen[4]; /* number of samples */
u_char start[4]; /* start marker */
u_char end[4]; /* end marker */
#define AKAI_SAMPLE1000_LOOPNUM 8
struct akai_sample1000loop_s loop[AKAI_SAMPLE1000_LOOPNUM];
u_char dummy3[2]; /* XXX 0x00 0x00 */
#define AKAI_SAMPLE1000_STPAIRA_NONE 0xffff /* value for none */
u_char stpaira[2]; /* address of sample header of partner in stereo pair (updated by sampler) */
u_char srate[2]; /* sample rate in Hz */
u_char hltoff; /* HOLD loop tune offset */
u_char dummy4[9]; /* XXX 0x00 ... 0x00 */
}; /* Note: should be 0x0096 Bytes */
/* Note: header is followed by sample data */
#define AKAI_SAMPLE1000_FTYPE 's' /* file type */
/* AKAI S3000 sample header */
struct akai_sample3000_s{
#define SAMPLE3000_BLOCKID SAMPLE1000_BLOCKID
struct akai_sample1000_s s1000;
u_char dummy1[42]; /* XXX 0x00 ... 0x00 */
}; /* Note: should be 0x00c0 Bytes */
/* Note: header is followed by sample data */
/* address multiplicand */
#define SAMPLE3000_STPAIRA_MULT 0x10
#define AKAI_SAMPLE3000_FTYPE ('s'+0x80) /* file type */
/* AKAI CD3000 CD-ROM sample parameters file */
/* Note: contains S3000 sample header */
#define AKAI_CDSAMPLE3000_FTYPE ('h'+0x80) /* file type */
/* AKAI S1000 program header */
struct akai_program1000_s{
#define PROGRAM1000_BLOCKID 0x01
u_char blockid; /* block ID */
#define PROGRAM1000_KGA_NONE 0x0000 /* value for none */
u_char kg1a[2]; /* address of keygroup 1 (updated by sampler) */
u_char name[AKAI_NAME_LEN]; /* program name (in RAM) */
u_char dummy1; /* XXX */
#define PROGRAM1000_MIDICH1_OMNI 0xff /* code for OMNI */
u_char midich1; /* MIDI channel number-1 or code */
u_char dummy2[2]; /* XXX */
u_char keylo; /* low MIDI key */
u_char keyhi; /* high MIDI key */
u_char oct; /* octave offset (signed) */
#define PROGRAM1000_AUXCH1_OFF 0xff /* code for OFF */
u_char auxch1; /* aux output channel number-1 or code */
u_char dummy3[18]; /* XXX */
u_char kgxf; /* keygroup crossfade enable */
u_char kgnum; /* number of keygroups */
u_char dummy4[107]; /* XXX */
}; /* Note: should be 0x0096 Bytes */
/* Note: header is followed by keygroups */
/* AKAI S1000 program keygroup: velocity zone */
struct akai_program1000kgvelzone_s{
u_char sname[AKAI_NAME_LEN]; /* sample name (in RAM) */
u_char vello; /* low MIDI velocity */
u_char velhi; /* high MIDI velocity */
u_char ctune; /* cents tune offset (signed) */
u_char stune; /* semitone tune offset (signed) */
u_char loud; /* loudness offset (signed) */
u_char filter; /* filter offset (signed) */
u_char pan; /* pan offset (signed) */
#define PROGRAM1000_PMODE_SAMPLE 0x00
#define PROGRAM1000_PMODE_LOOP 0x01
#define PROGRAM1000_PMODE_LOOPNOTREL 0x02
#define PROGRAM1000_PMODE_NOLOOP 0x03
#define PROGRAM1000_PMODE_TOEND 0x04
u_char pmode; /* playback mode */
u_char dummy1[2]; /* XXX */
#define PROGRAM1000KG_SHDRA_NONE 0xffff /* value for none */
u_char shdra[2]; /* address of sample header (updated by sampler) */
}; /* Note: should be 0x0018 Bytes */
/* AKAI S1000 program: keygroup */
struct akai_program1000kg_s{
#define PROGRAM1000KG_BLOCKID 0x02
u_char blockid; /* block ID */
u_char kgnexta[2]; /* address of next keygroup (updated by sampler) */
u_char keylo; /* low MIDI key */
u_char keyhi; /* high MIDI key */
u_char ctune; /* cents tune offset (signed) */
u_char stune; /* semitone tune offset (signed) */
u_char filter; /* filter */
u_char dummy1[22]; /* XXX */
u_char velxf; /* velocity crossfade enable */
u_char dummy2[3]; /* XXX */
#define PROGRAM1000KG_VELZONENUM 4 /* number of velocity zones per keygroup */
struct akai_program1000kgvelzone_s velzone[PROGRAM1000KG_VELZONENUM]; /* velocity zones */
u_char dummy3[2]; /* XXX */
u_char pconst[PROGRAM1000KG_VELZONENUM]; /* constant pitch enable for velocity zones */
u_char auxchoff[PROGRAM1000KG_VELZONENUM]; /* aux output channel offsets for velocity zones */
u_char dummy4[10]; /* XXX */
}; /* Note: should be 0x0096 Bytes */
#define AKAI_PROGRAM1000_FTYPE 'p' /* file type */
/* AKAI S3000 program header */
struct akai_program3000_s{
#define PROGRAM3000_BLOCKID PROGRAM1000_BLOCKID
struct akai_program1000_s s1000;
u_char dummy1[42]; /* XXX */
}; /* Note: should be 0x00c0 Bytes */
/* Note: header is followed by keygroups */
/* AKAI S3000 program: keygroup */
struct akai_program3000kg_s{
#define PROGRAM3000KG_BLOCKID PROGRAM1000KG_BLOCKID
struct akai_program1000kg_s s1000;
u_char dummy1[42]; /* XXX */
}; /* Note: should be 0x00c0 Bytes */
/* address multiplicands */
#define PROGRAM3000_KGA_MULT 0x10
#define PROGRAM3000_SHDRA_MULT 0x10
#define AKAI_PROGRAM3000_FTYPE ('p'+0x80) /* file type */
/* AKAI S1000 or S3000 drum settings descriptor */
struct akai_drum1000des_s{
u_char midich1; /* MIDI channel-1 */
u_char midinote; /* MIDI note */
u_char sens; /* sensitivity level */
u_char trig; /* trigger level */
u_char vcurv1; /* "V-curve"-1 */
u_char captt; /* capture time in msec */
u_char recovt; /* recovery time in msec */
u_char ontime; /* on-time in msec */
u_char dummy1; /* XXX */
}; /* Note: should be 0x0009 Bytes */
/* AKAI S1000 or S3000 drum settings file */
struct akai_drum1000_s{
#define DRUM1000_BLOCKID 0x01
u_char blockid; /* block ID */
u_char dummy1[2]; /* XXX */
u_char name[AKAI_NAME_LEN]; /* drum settings name (in RAM) */
#define DRUM1000_UNITNUM 2 /* number of units */
#define DRUM1000_INPUTNUM 8 /* number of drum trigger inputs per unit */
struct akai_drum1000des_s ddes1[DRUM1000_INPUTNUM]; /* drum setting descriptors for unit 1 */
u_char dummy2[3]; /* XXX */
struct akai_drum1000des_s ddes2[DRUM1000_INPUTNUM]; /* drum setting descriptors for unit 2 */
}; /* Note: should be 0x00a2 Bytes */
#define AKAI_DRUM1000_FTYPE 'd' /* file type */
#define AKAI_DRUM1000_FNAME "DRUM INPUTS " /* default file name */
/* AKAI S1100 or S3000 or S3000XL effects file */
/* Note: effects files of different system types are incompatible */
#define AKAI_FXFILE_FTYPE 'x' /* file type */
#define AKAI_FXFILE_FNAME "EFFECTS FILE" /* default file name */
#define AKAI_FXFILE_FSIZE 0x1c90 /* default file size */
#define FXFILE1100_BLOCKID 0x00
#define FXFILE3000_BLOCKID 0x00
#define FXFILE3000XL_BLOCKID 0x02
/* AKAI S1100 or S3000 cue/take-list header */
struct akai_cuelist_s{
#define CUELIST_BLOCKID 0x00
u_char blockid; /* block ID */
u_char dummy1[2]; /* XXX */
u_char name[AKAI_NAME_LEN]; /* cue/take-list name (in RAM) */
u_char dummy2[7]; /* XXX */
u_char cuenum; /* number of cues */
u_char dummy3[105]; /* XXX */
}; /* Note: should be 0x0080 Bytes */
/* Note: header is followed by cues */
/* AKAI S1100 or S3000 cue */
/* Note: depending on file/cue type, some struct elements are ignored */
struct akai_cue_s{
u_char name[AKAI_NAME_LEN]; /* program or take name */
u_char time[5]; /* time (BCD format) */
#define AKAI_CUETYPE_MOFF 0x00 /* program: MIDI note off */
#define AKAI_CUETYPE_MON 0x01 /* program: MIDI note on */
#define AKAI_CUETYPE_TOFF 0x02 /* DD take: off */
#define AKAI_CUETYPE_TON 0x03 /* DD take: on */
u_char type; /* cue type */
u_char midinote; /* MIDI note */
u_char midivel; /* MIDI velocity */
u_char pan; /* panning (signed) */
u_char stlvl; /* stereo output level */
u_char midich1; /* MIDI channel-1 */
u_char repeat1; /* repeat count-1 */
u_char fadein[2]; /* fade in time in ms */
u_char fadeout[2]; /* fade out time in ms */
u_char dummy1[4]; /* XXX */
}; /* Note: should be 0x0020 Bytes */
#define AKAI_QLFILE_FTYPE 'q' /* cue-list file type */
#define AKAI_QLFILE_FNAME "QL1 " /* default cue-list file name */
#define AKAI_TLFILE_FTYPE 't' /* take-list file type */
#define AKAI_TLFILE_FNAME "TL1 " /* default take-list file name */
/* AKAI S3000 multi file */
#define AKAI_MULTI3000_FTYPE ('m'+0x80) /* file type */
#define AKAI_MULTI3000_FNAME "MULTI FILE " /* default file name */
#define MULTI3000_BLOCKID 0x00
/* AKAI S1000 operating system file */
#define AKAI_SYS1000_FTYPE 'c' /* file type */
/* AKAI S3000 operating system file */
#define AKAI_SYS3000_FTYPE ('c'+0x80) /* file type */
/* AKAI CD3000 CD-ROM setup header */
/* Note: generic file header does not apply for this file type! */
struct akai_cdsetup3000_s{
u_char name[AKAI_NAME_LEN]; /* CD-ROM setup name (in RAM) */
u_char dummy1[3]; /* XXX */
u_char cdlabel[AKAI_NAME_LEN]; /* CD-ROM label */
}; /* Note: should be 0x006b Bytes */
/* followed by marked file entries */
/* marked file entry */
struct akai_cdsetup3000_entry_s{
u_char parti; /* partition index */
u_char voli; /* volume index */
u_char filei[2]; /* file index */
}; /* Note: should be 4 Bytes */
/* Note: unused entry is 0xff 0xff 0xff 0xff */
#define AKAI_CDSETUP3000_FTYPE 'T' /* file type */
/* Note: AKAI_CDSETUP3000_FTYPE is within range of file types for S900 */
#define AKAI_CDSETUP3000_FNAME "NEW CD SETUP" /* default file name */
/* Declarations */
extern int akai_file_info(struct file_s *fp,int verbose);
extern void akai_sample_info(struct file_s *fp,u_char *hdrp);
extern int akai_program_info(struct file_s *fp);
extern int akai_cuelist_info(struct file_s *fp);
extern int akai_takelist_info(struct file_s *fp);
extern int akai_drum1000_info(struct file_s *fp);
extern int akai_drum900_info(struct file_s *fp);
extern int akai_ovs900_info(struct file_s *fp);
extern int akai_cdsetup3000_info(struct file_s *fp);
extern int akai_fixramname(struct file_s *fp);
extern int akai_s900comprfile_updateuncompr(struct file_s *fp);
extern u_int akai_sample900_getsamplesize(struct file_s *fp);
extern void akai_sample900noncompr_sample2wav(u_char *sbuf,u_char *wavbuf,u_int samplecountpart);
extern void akai_sample900noncompr_wav2sample(u_char *sbuf,u_char *wavbuf,u_int samplecountpart);
extern u_int akai_sample900compr_getbits(u_char *buf,u_int bitpos,u_int bitnum);
extern u_int akai_sample900compr_sample2wav(u_char *sbuf,u_char *wavbuf,u_int sbufsiz,u_int wavbufsiz);
extern void akai_sample900compr_setbits(u_char *buf,u_int bitpos,u_int bitnum,u_int val);
extern int akai_sample900compr_wav2sample(u_char *sbuf,u_char *wavbuf,u_int samplecountpart);
extern int akai_sample900_noncompr2compr(struct file_s *fp,struct vol_s *volp);
extern int akai_sample900_compr2noncompr(struct file_s *fp,struct vol_s *volp);
#define SAMPLE2WAV_CHECK 1
#define SAMPLE2WAV_EXPORT 2
#define SAMPLE2WAV_CREATE 4
#define SAMPLE2WAV_ALL 0xff
extern int akai_sample2wav(struct file_s *fp,int wavfd,u_int *sizep,char **wavnamep,int what);
#define WAV2SAMPLE_OPEN 1
#define WAV2SAMPLE_OVERWRITE 2
extern int akai_wav2sample(int wavfd,char *wavname,struct vol_s *volp,u_int findex,
u_int type,int s9cflag,u_int osver,u_char *tagp,
u_int *bcountp,int what);
#endif /* !__AKAIUTIL_FILE_H */
+865
View File
@@ -0,0 +1,865 @@
/*
* Copyright (C) 2008,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#include "akaiutil_io.h"
#ifdef _VISUALCPP
/* for low-level floppy I/O, using fdrawcmd.sys */
#include "fdrawcmd.h" /* from http://simonowen.com/fdrawcmd/fdrawcmd.h */
HANDLE fldr_h[FLDRNUM]; /* handle for floppy drive */
u_int fldr_type[FLDRNUM]; /* floppy drive type */
PBYTE fldr_secbuf; /* DMA buffer for sector */
int
fldr_init(void)
{
u_int i;
for (i=0;i<FLDRNUM;i++){
fldr_h[i]=INVALID_HANDLE_VALUE;
fldr_type[i]=FLDR_TYPE_FLL; /* XXX */
}
/* allocate DMA buffer for sector */
fldr_secbuf=(PBYTE)VirtualAlloc(NULL,AKAI_FL_SECSIZE,MEM_COMMIT,PAGE_READWRITE);
if (fldr_secbuf==NULL){
PRINTF_ERR("fldr_init: cannot allocate DMA buffer\n");
return -1;
}
return 0;
}
void
fldr_end(void)
{
u_int i;
for (i=0;i<FLDRNUM;i++){
if (fldr_h[i]!=INVALID_HANDLE_VALUE){
CloseHandle(fldr_h[i]);
fldr_h[i]=INVALID_HANDLE_VALUE;
}
}
if (fldr_secbuf!=NULL){
VirtualFree(fldr_secbuf,0,MEM_RELEASE);
fldr_secbuf=NULL;
}
}
int
fldr_open(int fldrn,u_int fldrtype)
{
static char devname[32]; /* XXX */
HANDLE h;
DWORD version;
BYTE datarate;
DWORD ret;
if ((fldrn<0)||(fldrn>=FLDRNUM)){
PRINTF_ERR("fldr_open: invalid floppy drive number\n");
return -1;
}
if (fldr_h[fldrn]!=INVALID_HANDLE_VALUE){
PRINTF_ERR("fldr_open: floppy drive already opened\n");
return -1;
}
/* check driver */
version=0; /* invalid */
/* Note: must use GENERIC_READ|GENERIC_WRITE for DeviceIoControl() */
h=CreateFileA("\\\\.\\fdrawcmd",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if (h!=INVALID_HANDLE_VALUE){
if (!DeviceIoControl(h,IOCTL_FDRAWCMD_GET_VERSION,NULL,0,&version,sizeof(version),&ret,NULL)){
version=0; /* invalid */
}
CloseHandle(h);
}
if (version==0){
PRINTF_ERR("fldr_open: fdrawcmd.sys is not installed, see: http://simonowen.com/fdrawcmd/\n");
return -1;
}
if (HIWORD(version)!=HIWORD(FDRAWCMD_VERSION)){
PRINTF_ERR("fldr_open: the installed fdrawcmd.sys is not compatible with this program\n");
return -1;
}
/* open and init device */
sprintf(devname,"\\\\.\\fdraw%u",(u_int)fldrn);
/* Note: must use GENERIC_READ|GENERIC_WRITE for DeviceIoControl() */
h=CreateFileA(devname,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if (h==INVALID_HANDLE_VALUE){
PRINTF_ERR("fldr_open: cannot open floppy drive\n");
return -1;
}
if (fldrtype==FLDR_TYPE_FLH){
datarate=AKAI_FLH_DISK_DATARATE;
}else{
datarate=AKAI_FLL_DISK_DATARATE;
}
if (!DeviceIoControl(h,IOCTL_FD_SET_DATA_RATE,&datarate,sizeof(datarate),NULL,0,&ret,NULL)){
PRINTF_ERR("fldr_open: cannot set floppy data rate\n");
CloseHandle(h);
return -1;
}
if (!DeviceIoControl(h,IOCTL_FD_RESET,NULL,0,NULL,0,&ret,NULL)){
PRINTF_ERR("fldr_open: cannot reset floppy controller\n");
CloseHandle(h);
return -1;
}
/* save handle and type */
fldr_h[fldrn]=h;
fldr_type[fldrn]=fldrtype;
return 0;
}
int
fldr_checkfloppyinserted(int fldrn)
{
DWORD ret;
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)){
return -1;
}
/* check if no floppy inserted */
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
return -1;
}
return 0; /* floppy is inserted */
}
int
fldr_io_direct(int fldrn,u_int blk,u_char *buf,int mode)
{
BYTE cyl;
BYTE head;
BYTE sec;
DWORD ret;
FD_READ_WRITE_PARAMS rwp;
u_int retry;
int retval;
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)||(buf==NULL)){
return -1;
}
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
return -1;
}
if (fldr_type[fldrn]==FLDR_TYPE_FLH){
cyl=blk/(AKAI_FL_DISK_SIDES*AKAI_FLH_DISK_SECTORS);
head=1&(blk/AKAI_FLH_DISK_SECTORS);
sec=AKAI_FL_SECTOR_BASE+(blk%AKAI_FLH_DISK_SECTORS);
}else{
cyl=blk/(AKAI_FL_DISK_SIDES*AKAI_FLL_DISK_SECTORS);
head=1&(blk/AKAI_FLL_DISK_SECTORS);
sec=AKAI_FL_SECTOR_BASE+(blk%AKAI_FLL_DISK_SECTORS);
}
#ifdef DEBUG
PRINTF_OUT("fldr_io_direct: cyl=%u head=%u sec=%u\n",(u_int)cyl,(u_int)head,(u_int)sec);
#endif
/* check if no floppy inserted */
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
return -1;
}
/* goto track */
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_SEEK,&cyl,sizeof(cyl),NULL,0,&ret,NULL)){
return -1;
}
/* set parameters */
rwp.flags=FD_OPTION_MFM;
rwp.phead=head;
rwp.cyl=cyl;
rwp.head=head;
rwp.sector=sec;
rwp.size=AKAI_FL_SECTOR_SIZE_CODE;
rwp.eot=sec+1; /* for IOCTL_FDCMD_READ_DATA,IOCTL_FDCMD_WRITE_DATA: last sector number+1 !!! */
rwp.gap=0x0a;
rwp.datalen=0xff;
retval=0; /* no error so far */
if (mode==IO_BLKS_WRITE){
/* copy sector from buf to DMA buffer */
bcopy(buf,(u_char *)fldr_secbuf,AKAI_FL_SECSIZE);
for (retry=0;retry<FLDR_RETRYMAX;retry++){
/* write sector */
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_WRITE_DATA,&rwp,sizeof(rwp),(PVOID)fldr_secbuf,AKAI_FL_SECSIZE,&ret,NULL)){
break;
}
}
if (retry>=FLDR_RETRYMAX){
retval=-1; /* error */
}
}else{
for (retry=0;retry<FLDR_RETRYMAX;retry++){
/* read sector */
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_READ_DATA,&rwp,sizeof(rwp),(PVOID)fldr_secbuf,AKAI_FL_SECSIZE,&ret,NULL)){
break;
}
}
if (retry>=FLDR_RETRYMAX){
retval=-1; /* error */
}
/* copy sector from DMA buffer to buf */
/* Note: even if DeviceIoControl() above returned an error */
/* in this case, DMA buffer could contain leftover from last call */
/* or could contain correct complete or partial sector */
/* -> let caller decide what to do with buf in case of an error */
bcopy((u_char *)fldr_secbuf,buf,AKAI_FL_SECSIZE);
}
return retval;
}
int
fldr_format(int fldrn)
{
BYTE cyl;
BYTE head;
BYTE sec;
BYTE secnum;
BYTE secgap3;
BYTE secoffset;
BYTE trackskew;
DWORD ret;
static BYTE fpbuf[sizeof(FD_FORMAT_PARAMS)+sizeof(FD_ID_HEADER)*AKAI_FLH_DISK_SECTORS]; /* space for max. track size */
PFD_FORMAT_PARAMS fpp;
DWORD fpsize;
#ifndef FLDR_FORMAT_NOVERIFY
FD_READ_WRITE_PARAMS rwp;
#endif
u_int retry;
int retval;
if ((fldrn<0)||(fldrn>=FLDRNUM)||(fldr_h[fldrn]==INVALID_HANDLE_VALUE)){
return -1;
}
if (fldr_type[fldrn]==FLDR_TYPE_FLH){
secnum=AKAI_FLH_DISK_SECTORS;
secgap3=AKAI_FLH_SECTOR_GAP3;
secoffset=AKAI_FLH_SECTOR_OFFSET;
trackskew=AKAI_FLH_TRACK_SKEW;
}else{
secnum=AKAI_FLL_DISK_SECTORS;
secgap3=AKAI_FLL_SECTOR_GAP3;
secoffset=AKAI_FLL_SECTOR_OFFSET;
trackskew=AKAI_FLL_TRACK_SKEW;
}
retval=0; /* no error so far */
fpp=(PFD_FORMAT_PARAMS)fpbuf;
fpsize=sizeof(FD_FORMAT_PARAMS)+secnum*sizeof(FD_ID_HEADER);
for (cyl=0;cyl<AKAI_FL_DISK_TRACKS;cyl++){
/* check if no floppy inserted */
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FD_CHECK_DISK,NULL,0,NULL,0,&ret,NULL)){
PRINTF_OUT("\rno floppy inserted \n",((u_int)cyl)+1);
FLUSH_ALL;
return -1;
}
/* goto track */
if (!DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_SEEK,&cyl,sizeof(cyl),NULL,0,&ret,NULL)){
PRINTF_OUT("\rtrack %u - cannot seek track\n",((u_int)cyl)+1);
FLUSH_ALL;
return -1;
}
for (head=0;head<AKAI_FL_DISK_SIDES;head++){
PRINTF_OUT("\rtrack %u side %u",((u_int)cyl)+1,((u_int)head)+1);
FLUSH_ALL;
/* set parameters */
fpp->flags=FD_OPTION_MFM;
fpp->phead=head;
fpp->size=AKAI_FL_SECTOR_SIZE_CODE;
fpp->sectors=secnum;
fpp->gap=secgap3;
fpp->fill=AKAI_FL_SECTOR_FILL;
for (sec=0;sec<secnum;sec++){
fpp->Header[sec].cyl=cyl;
fpp->Header[sec].head=head;
fpp->Header[sec].sector=AKAI_FL_SECTOR_BASE+((secoffset+sec+cyl*(secnum-trackskew))%secnum);
fpp->Header[sec].size=AKAI_FL_SECTOR_SIZE_CODE;
}
#ifndef FLDR_FORMAT_NOVERIFY
rwp.flags=FD_OPTION_MFM;
rwp.phead=head;
rwp.cyl=cyl;
rwp.head=head;
rwp.sector=AKAI_FL_SECTOR_BASE;
rwp.size=AKAI_FL_SECTOR_SIZE_CODE;
rwp.eot=AKAI_FL_SECTOR_BASE+secnum-1; /* for IOCTL_FDCMD_VERIFY: last sector number !!! */
rwp.gap=0x0a;
rwp.datalen=0xff;
#endif
for (retry=0;retry<FLDR_RETRYMAX;retry++){
/* format track */
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_FORMAT_TRACK,fpp,fpsize,NULL,0,&ret,NULL)){
#ifndef FLDR_FORMAT_NOVERIFY
/* verify track */
if (DeviceIoControl(fldr_h[fldrn],IOCTL_FDCMD_VERIFY,&rwp,sizeof(rwp),NULL,0,&ret,NULL))
#endif
{
break;
}
}
}
if (retry>=FLDR_RETRYMAX){
PRINTF_OUT(" - cannot format track\n");
FLUSH_ALL;
#if 1
/* XXX ignore error, continue */
retval=-1;
#else
return -1;
#endif
}
}
}
PRINTF_OUT("\rdone \n");
FLUSH_ALL;
return retval;
}
#endif /* _VISUALCPP */
/* cache */
struct blk_cache_s blk_cache[BLK_CACHE_NUM];
int blk_cache_enable;
void
init_blk_cache(void)
{
int i;
for (i=0;i<BLK_CACHE_NUM;i++){
blk_cache[i].valid=0; /* free entry */
blk_cache[i].buf=NULL; /* not allocated yet */
}
}
void
free_blk_cache(void)
{
int i;
for (i=0;i<BLK_CACHE_NUM;i++){
if (blk_cache[i].buf!=NULL){ /* buffer allocated? */
/* free buffer */
free(blk_cache[i].buf);
blk_cache[i].valid=0; /* free entry */
blk_cache[i].buf=NULL; /* not allocated yet */
}
}
}
void
print_blk_cache(void)
{
int i;
#ifdef _VISUALCPP
PRINTF_OUT("nr fd fldrn start/B blksize blk age mod\n");
PRINTF_OUT("--------------------------------------------------------------\n");
#else /* !_VISUALCPP */
PRINTF_OUT("nr fd start/B blksize blk age mod\n");
PRINTF_OUT("--------------------------------------------------------\n");
#endif /* !_VISUALCPP */
for (i=0;i<BLK_CACHE_NUM;i++){
if (!blk_cache[i].valid){ /* free entry? */
continue; /* next */
}
#ifdef _VISUALCPP
PRINTF_OUT("%4i %3i %3i 0x%02x%08x 0x%04x 0x%04x 0x%08x %i\n",
i,
blk_cache[i].fd,
blk_cache[i].fldrn,
(u_int)(blk_cache[i].startoff>>32),
(u_int)(0xffffffff&blk_cache[i].startoff),
blk_cache[i].blksize,
blk_cache[i].blk,
blk_cache[i].age,
blk_cache[i].modified);
#else /* !_VISUALCPP */
PRINTF_OUT("%4i %3i 0x%02x%08x 0x%04x 0x%04x 0x%08x %i\n",
i,
blk_cache[i].fd,
(u_int)(blk_cache[i].startoff>>32),
(u_int)(0xffffffff&blk_cache[i].startoff),
blk_cache[i].blksize,
blk_cache[i].blk,
blk_cache[i].age,
blk_cache[i].modified);
#endif /* !_VISUALCPP */
}
#ifdef _VISUALCPP
PRINTF_OUT("--------------------------------------------------------------\n");
#else /* !_VISUALCPP */
PRINTF_OUT("--------------------------------------------------------\n");
#endif /* !_VISUALCPP */
}
int
find_blk_cache(int fd,
#ifdef _VISUALCPP
int fldrn,
#endif /* _VISUALCPP */
OFF64_T startoff,u_int blk,u_int blksize)
{
int i;
/* scan cache */
for (i=0;i<BLK_CACHE_NUM;i++){
if (blk_cache[i].buf==NULL){
continue; /* next */
}
if (!blk_cache[i].valid){ /* free? */
continue; /* next */
}
/* check if contained within cache */
/* Note: must check for blksize as well!!! */
if ((fd==blk_cache[i].fd)
#ifdef _VISUALCPP
&&(fldrn==blk_cache[i].fldrn)
#endif /* _VISUALCPP */
&&(startoff==blk_cache[i].startoff)
&&(blk==blk_cache[i].blk)
&&(blksize==blk_cache[i].blksize)){
break; /* found it */
}
}
if (i==BLK_CACHE_NUM){ /* none found? */
return -1;
}
return i;
}
void
blk_cache_aging(int i)
{
int j;
u_int agemin;
if ((i<0)||(i>=BLK_CACHE_NUM)||(!blk_cache[i].valid)){
return;
}
blk_cache[i].age=0; /* reset age */
/* find the youngest of the others */
agemin=BLK_CACHE_AGE_MAX;
for (j=0;j<BLK_CACHE_NUM;j++){
if (!blk_cache[j].valid){ /* free? */
continue; /* next */
}
if (j==i){
continue; /* next */
}
if (blk_cache[j].age<agemin){
agemin=blk_cache[j].age;
}
}
if (agemin==0){ /* somebody else too young? */
/* increment age of the others */
for (j=0;j<BLK_CACHE_NUM;j++){
if (j==i){
continue; /* next */
}
if (blk_cache[j].age<BLK_CACHE_AGE_MAX){
blk_cache[j].age++; /* increase age */
}
}
}
}
int
io_blks_direct(int fd,
#ifdef _VISUALCPP
int fldrn,
#endif /* _VISUALCPP */
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode)
{
int err;
int j,jmax;
u_int agemax;
u_int blk,blkmin,blkmax,blkchunk;
if (buf==NULL){
return -1;
}
#ifdef _VISUALCPP
if ((fd<0)&&(fldrn<0)){
return -1;
}
#else /* !_VISUALCPP */
if (fd<0){
return -1;
}
#endif /* !_VISUALCPP */
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
return -1;
}
/* Note: OFF64_T against overflow */
if ((((OFF64_T)bstart)+((OFF64_T)bsize))>(OFF64_T)0xffffffff){ /* XXX */
return -1;
}
if (bsize==0){
return 0; /* done */
}
if (!blk_cache_enable){ /* cache disabled? */
cachealloc=0; /* don't allocate cache */
}
if (cachealloc /* must allocate cache? */
#ifdef _VISUALCPP
||(fldrn>=0) /* or is floppy drive? */
#endif /* _VISUALCPP */
){
/* single blocks */
blkmin=bstart;
blkmax=bstart+bsize;
blkchunk=1;
}else{
/* all blocks at once */
blkmin=bstart;
blkmax=bstart+1; /* fake value: only once */
blkchunk=bsize;
}
for (blk=blkmin;blk<blkmax;blk++){
#ifdef _VISUALCPP
if (fldrn>=0){ /* is floppy drive? */
/* Note: ignore startoff if floppy drive */
if (fldr_io_direct(fldrn,blk,buf+(blk-blkmin)*blksize,mode)<0){
return -1;
}
}else /* no floppy drive */
#endif /* _VISUALCPP */
{
/* goto blk */
if (LSEEK64(fd,startoff+(OFF64_T)(blk*blksize),SEEK_SET)<0){
#ifdef DEBUG
PERROR("lseek");
#endif
return -1;
}
if (mode==IO_BLKS_WRITE){
/* write block(s) */
err=WRITE(fd,(void *)(buf+(blk-blkmin)*blksize),blkchunk*blksize);
if (err<0){
#ifdef DEBUG
PERROR("write");
#endif
return -1;
}
if (err!=(int)(blkchunk*blksize)){
#ifdef DEBUG
PRINTF_ERR("write: incomplete\n");
#endif
return -1;
}
}else{
/* read block(s) */
err=READ(fd,(void *)(buf+(blk-blkmin)*blksize),blkchunk*blksize);
if (err<0){
#ifdef DEBUG
PERROR("read");
#endif
return -1;
}
if (err!=(int)(blkchunk*blksize)){
#ifdef DEBUG
PRINTF_ERR("read: incomplete\n");
#endif
return -1;
}
}
}
if (cachealloc){ /* must allocate cache? */
/* find free entry or the oldest one */
agemax=0;
jmax=0; /* first guess */
for (j=0;j<BLK_CACHE_NUM;j++){
if (!blk_cache[j].valid){ /* free? */
jmax=j;
break; /* found one */
}
if (blk_cache[j].age>=agemax){ /* older or equal? */
agemax=blk_cache[j].age;
jmax=j;
}
}
/* old cache entry not free and modified? */
err=0;
if ((blk_cache[jmax].valid)&&(blk_cache[jmax].modified)&&(blk_cache[jmax].buf!=NULL)){
/* must flush this block */
if (io_blks_direct(blk_cache[jmax].fd,
#ifdef _VISUALCPP
blk_cache[jmax].fldrn,
#endif /* _VISUALCPP */
blk_cache[jmax].startoff,
(u_char *)blk_cache[jmax].buf,
blk_cache[jmax].blk,
1,
blk_cache[jmax].blksize,
0, /* don't alloc cache */
IO_BLKS_WRITE)<0){
PRINTF_ERR("cannot flush cache block 0x%08x of fd %i\n",blk_cache[jmax].blk,blk_cache[jmax].fd);
err=1; /* cannot allocate below */
}
}
if (!err){
if ((blk_cache[jmax].buf!=NULL)&&(blk_cache[jmax].blksize!=blksize)){ /* not compatible? */
/* free buffer */
free(blk_cache[jmax].buf);
blk_cache[jmax].buf=NULL;
}
if (blk_cache[jmax].buf==NULL){ /* buffer not allocated yet/anymore? */
/* need to allocate buffer */
if ((blk_cache[jmax].buf=(u_char *)malloc(blksize))==NULL){
PERROR("malloc");
err=1; /* cannot allocate below */
}
blk_cache[jmax].valid=0; /* free */
blk_cache[jmax].blksize=blksize;
}
}
if (!err){
/* allocate cache entry */
blk_cache[jmax].valid=1;
blk_cache[jmax].modified=0;
blk_cache[jmax].fd=fd;
#ifdef _VISUALCPP
blk_cache[jmax].fldrn=fldrn;
#endif /* _VISUALCPP */
blk_cache[jmax].startoff=startoff;
blk_cache[jmax].blk=blk;
blk_cache_aging(jmax); /* adjust ages */
/* copy data */
bcopy(buf+(blk-blkmin)*blksize,blk_cache[jmax].buf,blksize);
}
}
}
return 0;
}
/* Note: prior to changing blksize of any device/file, must flush cache first !!! */
int
flush_blk_cache(void)
{
int ret;
int i;
/* scan cache */
ret=0; /* no error so far */
for (i=0;i<BLK_CACHE_NUM;i++){
if (blk_cache[i].buf==NULL){
continue; /* next */
}
if (!blk_cache[i].valid){ /* free? */
continue; /* next */
}
if (!blk_cache[i].modified){ /* not modified? */
continue; /* next */
}
/* must write */
if (io_blks_direct(blk_cache[i].fd,
#ifdef _VISUALCPP
blk_cache[i].fldrn,
#endif /* _VISUALCPP */
blk_cache[i].startoff,
(u_char *)blk_cache[i].buf,
blk_cache[i].blk,
1,
blk_cache[i].blksize,
0, /* don't alloc cache */
IO_BLKS_WRITE)<0){
PRINTF_ERR("cannot flush cache block 0x%08x of fd %i\n",blk_cache[i].blk,blk_cache[i].fd);
/* XXX cannot do more now, maybe more luck next time */
ret=-1;
}else{
blk_cache[i].modified=0; /* done */
}
}
return ret;
}
int
io_blks(int fd,
#ifdef _VISUALCPP
int fldrn,
#endif /* _VISUALCPP */
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode)
{
int i;
u_int blk;
u_int chunkstart,chunksize;
if (buf==NULL){
return -1;
}
if ((mode!=IO_BLKS_READ)&&(mode!=IO_BLKS_WRITE)){
return -1;
}
/* Note: OFF64_T against overflow */
if ((((OFF64_T)bstart)+((OFF64_T)bsize))>(OFF64_T)0xffffffff){ /* XXX */
return -1;
}
#ifdef _VISUALCPP
if ((fd<0)&&(fldrn<0)){
return -1;
}
#else /* !_VISUALCPP */
if (fd<0){
return -1;
}
#endif /* !_VISUALCPP */
if (!blk_cache_enable){ /* cache disabled? */
cachealloc=0; /* don't allocate cache */
}
/* check every block */
chunkstart=bstart;
chunksize=0; /* no chunk of missing blocks so far */
for (blk=bstart;blk<(bstart+bsize);blk++){
if (blk_cache_enable){ /* cache enabled? */
/* look in cache */
i=find_blk_cache(fd,
#ifdef _VISUALCPP
fldrn,
#endif /* _VISUALCPP */
startoff,blk,blksize);
/* Note: no match for blk if blksize has changed!!! */
/* however, these cache entries can be reused if needed */
}else{
i=-1; /* not found in cache */
}
if (i<0){ /* not found in cache? */
if (chunksize==0){ /* new chunk of missing blocks? */
chunkstart=blk; /* start of chunk */
}
chunksize++; /* one more missing block */
}else{
/* found in cache */
/* Note: now, blk_cache[i].buf!=NULL */
/* Note: must do cache-I/O first, since io_blks_direct could steal i from cache */
if (mode==IO_BLKS_WRITE){
/* copy to cache */
bcopy(buf+(blk-bstart)*blksize,blk_cache[i].buf,blksize);
blk_cache[i].modified=1; /* modified */
}else{
/* copy from cache */
bcopy(blk_cache[i].buf,buf+(blk-bstart)*blksize,blksize);
}
blk_cache_aging(i); /* adjust ages */
/* chunk of missing blocks pending? */
if (chunksize>0){
/* must read or write */
if (io_blks_direct(fd,
#ifdef _VISUALCPP
fldrn,
#endif /* _VISUALCPP */
startoff,
(u_char *)(buf+(chunkstart-bstart)*blksize),
chunkstart,
chunksize,
blksize,
cachealloc,
mode)<0){
return -1;
}
chunksize=0; /* no chunk of missing blocks anymore */
}
}
}
/* one last time: chunk of missing blocks pending? */
if (chunksize>0){
/* must read or write */
if (io_blks_direct(fd,
#ifdef _VISUALCPP
fldrn,
#endif /* _VISUALCPP */
startoff,
(u_char *)(buf+(chunkstart-bstart)*blksize),
chunkstart,
chunksize,
blksize,
cachealloc,
mode)<0){
return -1;
}
chunksize=0; /* no chunk of missing blocks anymore */
}
return 0;
}
/* EOF */
+137
View File
@@ -0,0 +1,137 @@
#ifndef __AKAIUTIL_IO_H
#define __AKAIUTIL_IO_H
/*
* Copyright (C) 2008,2010,2012,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#ifdef _VISUALCPP
/* for low-level floppy I/O, using fdrawcmd.sys */
#include "fdrawcmd.h" /* from http://simonowen.com/fdrawcmd/fdrawcmd.h */
/* definitions for low-level format of floppy disks for AKAI samplers */
#define AKAI_FL_DISK_SIDES 2 /* sides per disk */
#define AKAI_FL_DISK_TRACKS 80 /* tracks per side */
#define AKAI_FLL_DISK_SECTORS 5 /* sectors per track for low-density floppy */
#define AKAI_FLH_DISK_SECTORS 10 /* sectors per track for high-density floppy */
#define AKAI_FLL_DISK_DATARATE FD_RATE_250K /* data rate for low-density floppy */
#define AKAI_FLH_DISK_DATARATE FD_RATE_500K /* data rate for high-density floppy */
#define AKAI_FL_SECTOR_SIZE_CODE 3 /* sector size code: 3 -> (128<<3)==1024 */
#define AKAI_FLL_SECTOR_GAP3 0x74 /* gap3 size between sectors for low-density floppy */
#define AKAI_FLH_SECTOR_GAP3 0x74 /* gap3 size between sectors for high-density floppy */
#define AKAI_FL_SECTOR_FILL 0x00 /* fill byte for formatted sectors */
#define AKAI_FL_SECTOR_BASE 1 /* first sector number on track */
#define AKAI_FLL_SECTOR_OFFSET 3 /* sector number offset for low-density floppy */
#define AKAI_FLH_SECTOR_OFFSET 6 /* sector number offset for high-density floppy */
#define AKAI_FLL_TRACK_SKEW 2 /* skew to the same sector on the next track for low-density floppy */
#define AKAI_FLH_TRACK_SKEW 4 /* skew to the same sector on the next track for high-density floppy */
/* low-level floppy sector size */
#define AKAI_FL_SECSIZE 0x0400 /* 1KB */
/* Note: must be == AKAI_FL_BLOCKSIZE (floppy filesystem blocksize, defined in akaiutil.h) */
#if defined(AKAI_FL_BLOCKSIZE)&&(AKAI_FL_SECSIZE!=AKAI_FL_BLOCKSIZE)
#error "AKAI_FL_SECSIZE!=AKAI_FL_BLOCKSIZE"
#endif
#ifndef FLDRNUM
#define FLDRNUM 2 /* XXX max. number of floppy drives */
#endif
extern HANDLE fldr_h[FLDRNUM]; /* handle for floppy drive */
#define FLDR_TYPE_FLL 0 /* low-density floppy */
#define FLDR_TYPE_FLH 1 /* high-density floppy */
extern u_int fldr_type[FLDRNUM]; /* floppy drive type */
extern PBYTE fldr_secbuf; /* DMA buffer for sector */
#ifndef FLDR_RETRYMAX
#define FLDR_RETRYMAX 5 /* XXX max. number of retries for floppy I/O */
#endif
#endif /* _VISUALCPP */
/* cache */
struct blk_cache_s{
int valid;
int modified;
int fd;
#ifdef _VISUALCPP
int fldrn;
#endif /* _VISUALCPP */
OFF64_T startoff;
u_int blk;
u_int blksize;
#define BLK_CACHE_AGE_MAX 0xffffffff /* XXX max. age */
u_int age; /* age */
u_char *buf;
};
#ifndef BLK_CACHE_NUM
#define BLK_CACHE_NUM 512 /* XXX */
#endif
extern struct blk_cache_s blk_cache[BLK_CACHE_NUM];
extern int blk_cache_enable;
#define IO_BLKS_READ 0
#define IO_BLKS_WRITE 1
/* Declarations */
#ifdef _VISUALCPP
extern int fldr_init(void);
extern void fldr_end(void);
extern int fldr_open(int fldrn,u_int fldrtype);
extern int fldr_checkfloppyinserted(int fldrn);
extern int fldr_io_direct(int fldrn,u_int blk,u_char *buf,int mode);
extern int fldr_format(int fldrn);
#endif /* _VISUALCPP */
extern void init_blk_cache(void);
extern void free_blk_cache(void);
extern void print_blk_cache(void);
extern int find_blk_cache(int fd,
#ifdef _VISUALCPP
int fldrnr,
#endif
OFF64_T startoff,u_int blk,u_int blksize);
extern void blk_cache_aging(int i);
extern int io_blks_direct(int fd,
#ifdef _VISUALCPP
int fldrn,
#endif
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode);
extern int flush_blk_cache(void);
extern int io_blks(int fd,
#ifdef _VISUALCPP
int fldrn,
#endif
OFF64_T startoff,u_char *buf,u_int bstart,u_int bsize,u_int blksize,int cachealloc,int mode);
#endif /* !__AKAIUTIL_IO_H */
+5651
View File
File diff suppressed because it is too large Load Diff
+1040
View File
File diff suppressed because it is too large Load Diff
+68
View File
@@ -0,0 +1,68 @@
#ifndef __AKAIUTIL_TAKE_H
#define __AKAIUTIL_TAKE_H
/*
* Copyright (C) 2012,2018,2019 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#include "akaiutil.h"
/* AKAI DD takes */
/* Note: all data types are little endian */
/* S1100/S3000 DD take header (directory entry in DD partition header) */
/* XXX should be defined in akaiutil_take.h, but must be in akaiutil.h due to dependencies */
struct akai_ddtake_s;
/* file name ending for exported DD take */
#define AKAI_DDTAKE_FNAMEEND ".TK"
/* Declarations */
extern int akai_ddtake_info(struct part_s *pp,u_int ti,int verbose);
extern int akai_import_take(int inpfd,struct part_s *pp,struct akai_ddtake_s *tp,u_int ti,u_int csizes,u_int csizee);
extern int akai_export_take(int outfd,struct part_s *pp,struct akai_ddtake_s *tp,u_int csizes,u_int csizee,u_int cstarts,u_int cstarte);
#define TAKE2WAV_CHECK 1
#define TAKE2WAV_EXPORT 2
#define TAKE2WAV_CREATE 4
#define TAKE2WAV_ALL 0xff
extern int akai_take2wav(struct part_s *pp,u_int ti,int wavfd,u_int *sizep,char **wavnamep,int what);
#define WAV2TAKE_OPEN 1
extern int akai_wav2take(int wavfd,char *wavname,struct part_s *pp,u_int ti,u_int *bcountp,int what);
extern int akai_take_setenv(struct part_s *pp,u_int cstarts,u_int samplesize,u_char *envbuf,u_int envsiz);
#endif /* !__AKAIUTIL_TAKE_H */
+1235
View File
File diff suppressed because it is too large Load Diff
+95
View File
@@ -0,0 +1,95 @@
#ifndef __AKAIUTIL_TAR_H
#define __AKAIUTIL_TAR_H
/*
* Copyright (C) 2008,2010,2012,2019,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
/* tar header */
/* Note: numbers in octal, trailing '\0' */
struct tar_head_s{
#define TAR_NAMELEN 100 /* incl. '\0' */
char name[TAR_NAMELEN];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[7];
char space;
char type;
char linkname[TAR_NAMELEN];
#define TAR_USTAR "ustar\00000"
char ustar[8];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
#define TAR_PREFIXLEN 155 /* incl. '\0' */
char prefix[TAR_PREFIXLEN];
char zero[12];
};
/* should be 512 bytes */
#define TAR_BLOCKSIZE 512 /* in bytes */
#define TAR_TYPE_REG '0' /* regular file */
#define TAR_TYPE_REG0 '\0' /* regular file */
#define TAR_TYPE_DIR '5' /* directory */
#define TAR_TAILZERO_BLOCKS 6 /* number or zero blocks at file end */
/* Declarations */
extern u_int tar_checksum(u_char *hp);
#define TAR_EXPORT_DISK 0x0001
#define TAR_EXPORT_PART 0x0002
#define TAR_EXPORT_VOL 0x0004
#define TAR_EXPORT_FILE 0x0008
#define TAR_EXPORT_DDFILE 0x0010
#define TAR_EXPORT_TAGSFILE 0x0020
#define TAR_EXPORT_VOLPARAMFILE 0x0040
#define TAR_EXPORT_ANYFILE (TAR_EXPORT_FILE|TAR_EXPORT_DDFILE|TAR_EXPORT_TAGSFILE|TAR_EXPORT_VOLPARAMFILE)
#define TAR_EXPORT_WAV 0x1000
extern int tar_export(int fd,struct disk_s *dp,struct part_s *pp,struct vol_s *vp,struct file_s *fp,u_int ti,u_int flags,int verbose,u_char *filtertagp);
extern int tar_export_vol(int fd,struct vol_s *vp,u_int flags,int verbose,u_char *filtertagp);
extern int tar_export_part(int fd,struct part_s *pp,u_int flags,int verbose,u_char *filtertagp);
extern int tar_export_disk(int fd,struct disk_s *dp,u_int flags,int verbose,u_char *filtertagp);
extern int tar_export_alldisks(int fd,u_int flags,int verbose,u_char *filtertagp);
extern int tar_export_curdir(int fd,int verbose,u_int flags);
extern int tar_export_tailzero(int fd);
#define TAR_IMPORT_WAV 0x0100
#define TAR_IMPORT_WAVS9 0x1000
#define TAR_IMPORT_WAVS9C 0x2000
#define TAR_IMPORT_WAVS1 0x4000
#define TAR_IMPORT_WAVS3 0x8000
extern int tar_import_curdir(int fd,u_int vtype0,int verbose,u_int flags);
#endif /* !__AKAIUTIL_TAR_H */
+482
View File
@@ -0,0 +1,482 @@
/*
* Copyright (C) 2010,2019 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#include "akaiutil_wav.h"
int
wav_write_head(int outdes,
u_int datasize,u_int chnr,u_int samprate,u_int bitnr,
u_int extrasize)
{
struct wav_riffhead_s wavriffhead;
struct wav_chunkhead_s wavchunkhead;
struct wav_fmthead_s wavfmthead;
u_int drate;
/* create WAVE RIFF header */
bzero(&wavriffhead,sizeof(struct wav_riffhead_s));
bcopy(WAV_RIFFHEAD_RIFFSTR,wavriffhead.riffstr,4);
{
u_int fsize;
fsize=WAV_HEAD_SIZE-sizeof(struct wav_chunkhead_s)+datasize+extrasize;
wavriffhead.fsize[0]=0xff&fsize;
wavriffhead.fsize[1]=0xff&(fsize>>8);
wavriffhead.fsize[2]=0xff&(fsize>>16);
wavriffhead.fsize[3]=0xff&(fsize>>24);
}
bcopy(WAV_RIFFHEAD_WAVESTR,wavriffhead.wavestr,4);
/* write WAVE RIFF header */
if (WRITE(outdes,&wavriffhead,sizeof(struct wav_riffhead_s))!=sizeof(struct wav_riffhead_s)){
PRINTF_ERR("cannot write WAVE RIFF header\n");
return -1;
}
/* create FMT chunk header */
bcopy(WAV_CHUNKHEAD_FMTSTR,wavchunkhead.typestr,4);
{
u_int csize;
csize=sizeof(struct wav_fmthead_s);
wavchunkhead.csize[0]=0xff&csize;
wavchunkhead.csize[1]=0xff&(csize>>8);
wavchunkhead.csize[2]=0xff&(csize>>16);
wavchunkhead.csize[3]=0xff&(csize>>24);
}
/* write chunk header */
if (WRITE(outdes,&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
PRINTF_ERR("cannot write WAVE FMT header\n");
return -1;
}
/* set FMT header */
wavfmthead.ftag[0]=0xff&WAV_HEAD_FTAG_PCM;
wavfmthead.ftag[1]=0xff&(WAV_HEAD_FTAG_PCM>>8);
wavfmthead.chnr[0]=0xff&chnr;
wavfmthead.chnr[1]=0xff&(chnr>>8);
wavfmthead.srate[0]=0xff&samprate;
wavfmthead.srate[1]=0xff&(samprate>>8);
wavfmthead.srate[2]=0xff&(samprate>>16);
wavfmthead.srate[3]=0xff&(samprate>>24);
drate=chnr*samprate*(bitnr/8); /* chnr!!! */
wavfmthead.drate[0]=0xff&drate;
wavfmthead.drate[1]=0xff&(drate>>8);
wavfmthead.drate[2]=0xff&(drate>>16);
wavfmthead.drate[3]=0xff&(drate>>24);
wavfmthead.balign[0]=0xff&((bitnr/8)*chnr); /* chnr!!! */
wavfmthead.balign[1]=0xff&(((bitnr/8)*chnr)>>8); /* chnr!!! */
wavfmthead.bitnr[0]=0xff&bitnr;
wavfmthead.bitnr[1]=0xff&(bitnr>>8);
/* write WAVE FMT header */
if (WRITE(outdes,&wavfmthead,sizeof(struct wav_fmthead_s))!=sizeof(struct wav_fmthead_s)){
PRINTF_ERR("cannot write WAVE FMT header\n");
return -1;
}
/* create WAVE DATA chunk header */
bcopy(WAV_CHUNKHEAD_DATASTR,wavchunkhead.typestr,4);
wavchunkhead.csize[0]=0xff&datasize;
wavchunkhead.csize[1]=0xff&(datasize>>8);
wavchunkhead.csize[2]=0xff&(datasize>>16);
wavchunkhead.csize[3]=0xff&(datasize>>24);
/* write chunk header */
if (WRITE(outdes,&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
PRINTF_ERR("cannot write WAVE DATA header\n");
return -1;
}
return 0;
}
int
wav_read_head(int indes,
u_int *bcountp,
u_int *datasizep,u_int *chnrp,u_int *sampratep,u_int *bitnrp,
u_int *extrasizep,
char **errstrp)
{
struct wav_riffhead_s wavriffhead;
struct wav_chunkhead_s wavchunkhead;
struct wav_fmthead_s wavfmthead;
u_int i;
u_int bcount;
u_int remain;
u_int csize;
u_int chnr;
u_int samprate;
u_int bitnr;
bcount=0; /* no bytes read yet */
/* read WAVE RIFF header */
if (READ(indes,(char *)&wavriffhead,sizeof(struct wav_riffhead_s))!=sizeof(struct wav_riffhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE RIFF header";
}
return -1;
}
bcount+=sizeof(struct wav_riffhead_s);
/* check riffstr */
for (i=0;i<4;i++){
if (WAV_RIFFHEAD_RIFFSTR[i]!=wavriffhead.riffstr[i]){
if (errstrp!=NULL){
*errstrp="no RIFF";
}
return -1;
}
}
/* determine remaining file size */
remain=wavriffhead.fsize[0]
+(wavriffhead.fsize[1]<<8)
+(wavriffhead.fsize[2]<<16)
+(wavriffhead.fsize[3]<<24);
if (remain<sizeof(struct wav_riffhead_s)-sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
remain-=sizeof(struct wav_riffhead_s)-sizeof(struct wav_chunkhead_s);
/* check wavestr */
for (i=0;i<4;i++){
if (WAV_RIFFHEAD_WAVESTR[i]!=wavriffhead.wavestr[i]){
if (errstrp!=NULL){
*errstrp="no WAVE";
}
return -1;
}
}
/* search for fmt chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE FMT header";
}
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_FMTSTR[i]!=wavchunkhead.typestr[i]){
break; /* not fmt chunk */
}
}
if (i==4){
break; /* found fmt */
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
if (errstrp!=NULL){
*errstrp="lseek WAVE FMT header";
}
return -1;
}
bcount+=csize;
remain-=csize;
}
if (csize!=sizeof(struct wav_fmthead_s)){
if (errstrp!=NULL){
*errstrp="invalid FMT csize";
}
return -1;
}
/* read rest of fmt chunk */
if (READ(indes,(char *)&wavfmthead,sizeof(struct wav_fmthead_s))!=sizeof(struct wav_fmthead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE FMT header";
}
return -1;
}
bcount+=sizeof(struct wav_fmthead_s);
remain-=sizeof(struct wav_fmthead_s);
/* check ftag */
/* XXX allow only PCM */
if ((wavfmthead.ftag[0]!=(0xff&WAV_HEAD_FTAG_PCM))
||(wavfmthead.ftag[1]!=(0xff&(WAV_HEAD_FTAG_PCM>>8)))){
if (errstrp!=NULL){
*errstrp="invalid ftag, must be PCM format";
}
return -1;
}
/* get chnr */
chnr=wavfmthead.chnr[0]
+(wavfmthead.chnr[1]<<8);
if (chnr==0){
if (errstrp!=NULL){
*errstrp="invalid chnr";
}
return -1;
}
/* set samprate */
samprate=wavfmthead.srate[0]
+(wavfmthead.srate[1]<<8)
+(wavfmthead.srate[2]<<16)
+(wavfmthead.srate[3]<<24);
/* XXX check drate: must be chnr*samprate*(bitnr/8) */
/* get bitnr */
bitnr=wavfmthead.bitnr[0]
+(wavfmthead.bitnr[1]<<8);
if (bitnr==0){
if (errstrp!=NULL){
*errstrp="invalid bitnr";
}
return -1;
}
/* XXX check balign: must be (bitnr/8)*chnr */
/* search for data chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))!=sizeof(struct wav_chunkhead_s)){
if (errstrp!=NULL){
*errstrp="read WAVE DATA header";
}
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
if (errstrp!=NULL){
*errstrp="invalid file size";
}
return -1;
}
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_DATASTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
break; /* found fmt */
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
if (errstrp!=NULL){
*errstrp="lseek WAVE DATA header";
}
return -1;
}
bcount+=csize;
remain-=csize;
}
if (csize%chnr!=0){
if (errstrp!=NULL){
*errstrp="invalid DATA csize";
}
return -1;
}
if (bcountp!=NULL){
*bcountp=bcount;
}
if (datasizep!=NULL){
*datasizep=csize;
}
if (chnrp!=NULL){
*chnrp=chnr;
}
if (sampratep!=NULL){
*sampratep=samprate;
}
if (bitnrp!=NULL){
*bitnrp=bitnr;
}
if (extrasizep!=NULL){
*extrasizep=remain-csize;
}
return 0;
}
#ifndef WAV_AKAIHEAD_DISABLE
int
wav_find_akaihead(int indes,u_int *bcountp,u_int *csizep,u_int remain,u_int searchtype)
{
struct wav_chunkhead_s wavchunkhead;
u_int bcount;
u_int csize;
u_int type;
u_int i;
bcount=0; /* no bytes read yet */
csize=0; /* no chunk yet */
type=WAV_AKAIHEADTYPE_NONE; /* no AKAI header chunk found yet */
/* search for AKAI header chunk */
for (;;){
/* read next chunk */
if (remain<sizeof(struct wav_chunkhead_s)){
break;
}
if (READ(indes,(char *)&wavchunkhead,sizeof(struct wav_chunkhead_s))<0){
PRINTF_ERR("cannot read WAV chunk");
return -1;
}
bcount+=sizeof(struct wav_chunkhead_s);
remain-=sizeof(struct wav_chunkhead_s);
/* get csize */
csize=wavchunkhead.csize[0]
+(wavchunkhead.csize[1]<<8)
+(wavchunkhead.csize[2]<<16)
+(wavchunkhead.csize[3]<<24);
if (remain<csize){
break;
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE900)){
/* check if S900 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS900SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE900;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE1000)){
/* check if S1000 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS1000SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE1000;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_SAMPLE3000)){
/* check if S3000 sample header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIS3000SAMPLEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_SAMPLE3000;
break;
}
}
if ((searchtype==WAV_AKAIHEADTYPE_NONE)||(searchtype==WAV_AKAIHEADTYPE_DDTAKE)){
/* check if DD take header chunk */
for (i=0;i<4;i++){
if (WAV_CHUNKHEAD_AKAIDDTAKEHEADSTR[i]!=wavchunkhead.typestr[i]){
break; /* not data chunk */
}
}
if (i==4){
/* found */
type=WAV_AKAIHEADTYPE_DDTAKE;
break;
}
}
/* skip rest of chunk */
if (LSEEK64(indes,(OFF64_T)csize,SEEK_CUR)<0){
PERROR("cannot lseek WAV chunk");
return -1;
}
bcount+=csize;
remain-=csize;
}
if (type==WAV_AKAIHEADTYPE_NONE){ /* no AKAI header chunk found? */
csize=0;
}
if (bcountp!=NULL){
*bcountp=bcount;
}
if (csizep!=NULL){
*csizep=csize;
}
return (int)type;
}
#endif
/* EOF */
+99
View File
@@ -0,0 +1,99 @@
#ifndef __AKAIUTIL_WAV_H
#define __AKAIUTIL_WAV_H
/*
* Copyright (C) 2010,2019 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
/* RIFF WAVE format header */
/* Note: WAV-file is little-endian!!! */
struct wav_riffhead_s{
/* begin RIFFWAVEChunk */
#define WAV_RIFFHEAD_RIFFSTR "RIFF"
char riffstr[4]; /* must be "RIFF" */
u_char fsize[4]; /* following file-size in Bytes */
#define WAV_RIFFHEAD_WAVESTR "WAVE"
char wavestr[4]; /* must be "WAVE" */
/* end RIFFWAVEChunk */
};
struct wav_chunkhead_s{
char typestr[4]; /* chunk type */
u_char csize[4]; /* following chunk-size in Bytes */
};
#define WAV_CHUNKHEAD_FMTSTR "fmt "
#define WAV_CHUNKHEAD_DATASTR "data"
struct wav_fmthead_s{
/* continued FormatChunk */
#define WAV_HEAD_FTAG_PCM 0x0001 /* 1: PCM/umcompressed */
u_char ftag[2]; /* format tag */
u_char chnr[2]; /* number of channels */
u_char srate[4]; /* sample rate in samples/sec */
u_char drate[4]; /* total data rate in Bytes/sec */
u_char balign[2]; /* number of Bytes per sample * chnr */
u_char bitnr[2]; /* number of Bits per sample */
/* end FormatChunk */
};
#define WAV_HEAD_SIZE (sizeof(struct wav_riffhead_s)+sizeof(struct wav_chunkhead_s)+sizeof(struct wav_fmthead_s)+sizeof(struct wav_chunkhead_s))
#ifndef WAV_AKAIHEAD_DISABLE
/* AKAI header chunks */
#define WAV_CHUNKHEAD_AKAIS900SAMPLEHEADSTR "S9H "
#define WAV_CHUNKHEAD_AKAIS1000SAMPLEHEADSTR "S1H "
#define WAV_CHUNKHEAD_AKAIS3000SAMPLEHEADSTR "S3H "
#define WAV_CHUNKHEAD_AKAIDDTAKEHEADSTR "TKH "
#endif
/* Declarations */
extern int wav_write_head(int outdes,
u_int datasize,u_int chnr,u_int samprate,u_int bitnr,
u_int extrasize);
extern int wav_read_head(int indes,u_int *bcountp,
u_int *datasizep,u_int *chnrp,u_int *sampratep,u_int *bitnrp,
u_int *extrasizep,
char **errstrp);
#ifndef WAV_AKAIHEAD_DISABLE
#define WAV_AKAIHEADTYPE_NONE 0x00
#define WAV_AKAIHEADTYPE_SAMPLE900 0x09
#define WAV_AKAIHEADTYPE_SAMPLE1000 0x01
#define WAV_AKAIHEADTYPE_SAMPLE3000 0x03
#define WAV_AKAIHEADTYPE_DDTAKE 0xdd
int wav_find_akaihead(int indes,u_int *bcountp,u_int *csizep,u_int remain,u_int searchtype);
#endif
#endif /* !__AKAIUTIL_WAV_H */
+237
View File
@@ -0,0 +1,237 @@
#ifndef __COMMONINCLUDE_H
#define __COMMONINCLUDE_H
/*
* Copyright (C) 2008,2010,2012,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef _VISUALCPP
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
/*#include <unistd.h>*/
/*#include <strings.h>*/
#include <string.h>
#include <ctype.h>
#include <time.h>
typedef unsigned char u_char;
typedef unsigned int u_int;
typedef unsigned long u_long;
typedef int ssize_t;
#ifndef SSIZE_MAX
#define SSIZE_MAX INT_MAX
#endif /* !SSIZE_MAX */
#define INT64 __int64
#define U_INT64 unsigned __int64
#define OFF_T __int64
#define OFF64_T __int64
#define OPEN _open
#define CLOSE _close
#define READ _read
#define WRITE _write
/* default lseek and off_t cannot handle offsets>=2GB! */
#define LSEEK _lseeki64
#define LSEEK64 _lseeki64
extern int strcasecmp(const char *s1,const char *s2);
extern int strncasecmp(const char *s1,const char *s2,size_t n);
/* getopt */
/*#include <unistd.h>*/
extern int getopt(int argc,char * const argv[],const char *optstring);
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
/* Note: returned value of _snprintf_s() can differ from returned value of snprintf() */
#define SNPRINTF(x,y,...) _snprintf_s((x),(y),_TRUNCATE,__VA_ARGS__)
/* XXX ignore returned value */
#define SYSTEM(x) {system(x);}
/* local (external) filesystem */
#include <direct.h>
#define LCHDIR(d) _chdir(d)
#define LDIR SYSTEM("dir")
#define LDELFILE(x,y,n) {_snprintf_s((x),(y),_TRUNCATE,"del /q /f \"%s\"",(n)); SYSTEM(x);}
/* play external WAV file */
#define PLAYWAV_PREPARE(x,y,n) SNPRINTF((x),(y),"%s",(n))
#define PLAYWAV_START(x) PlaySoundA((LPCSTR)(x),NULL,SND_ASYNC|SND_FILENAME|SND_NODEFAULT)
#define PLAYWAV_STOP PlaySoundA(NULL,NULL,0)
#else /* !_VISUALCPP */
/* e.g. UNIX-like systems or cygwin */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#define INT64 __int64_t
#define U_INT64 __uint64_t
#define OFF_T off_t
#define OFF64_T int64_t
#ifndef NOT_MYLSEEK64
/* own 64bit version of lseek */
extern OFF64_T mylseek64(int filedes,OFF64_T offset,int whence);
#define LSEEK64 mylseek64
#endif
#ifndef __CYGWIN__
/* e.g. UNIX-like systems */
/* getopt */
#include <unistd.h>
extern int getopt(int argc,char * const argv[],const char *optstring);
extern char *optarg;
extern int optind;
extern int opterr;
extern int optopt;
#endif /* !__CYGWIN__*/
#define SNPRINTF(x,y,...) snprintf((x),(y),__VA_ARGS__)
/* XXX ignore returned value */
#define SYSTEM(x) {if (system(x)<0){;}}
/* local (external) filesystem */
#include <dirent.h>
#define LCHDIR(d) chdir(d)
#define LDIR SYSTEM("ls -la")
#define LDELFILE(x,y,n) {SNPRINTF((x),(y),"rm -f \"%s\"",(n)); SYSTEM(x);}
/* play external WAV file */
#ifndef PLAYWAV_CMD
#ifdef __APPLE__
#define PLAYWAV_CMD "afplay"
#else /* !__APPLE__ */
/* use PulseAudio */
#define PLAYWAV_CMD "paplay"
#endif /* !__APPLE__ */
#endif /* !PLAYWAV_CMD */
#define PLAYWAV_PREPARE(x,y,n) snprintf((x),(y),PLAYWAV_CMD " \"%s\" > /dev/null 2>&1 &",(n))
#define PLAYWAV_START(x) SYSTEM((const char *)(x))
#define PLAYWAV_STOP SYSTEM("killall " PLAYWAV_CMD " > /dev/null 2>&1")
#endif /* !_VISUALCPP */
#include <math.h>
/* O_BINARY important for Windows-based systems (esp. cygwin or VC++) */
#ifndef O_BINARY
#define O_BINARY 0
#endif /* !O_BINARY */
#ifndef OPEN
#define OPEN open
#endif
#ifndef CLOSE
#define CLOSE close
#endif
#ifndef READ
#define READ read
#endif
#ifndef WRITE
#define WRITE write
#endif
#ifndef LSEEK
#define LSEEK lseek
#endif
#ifndef LSEEK64
#define LSEEK64 lseek64
#endif
extern void bcopy(const void *src,void *dst,size_t len);
extern void bzero(void *b,size_t len);
#ifndef STRHEX_TO_UINT64
extern U_INT64 my_strhex_to_uint64(char *s);
#define STRHEX_TO_UINT64 my_strhex_to_uint64
#define USE_MY_STRHEX_TO_UINT64
#endif
#ifndef STRDEC_TO_UINT64
extern U_INT64 my_strdec_to_uint64(char *s);
#define STRDEC_TO_UINT64 my_strdec_to_uint64
#define USE_MY_STRDEC_TO_UINT64
#endif
#ifdef UI_INCLUDE
/* external user interface */
#include UI_INCLUDE
#endif
/* console I/O */
#ifndef FGETS
#define FGETS fgets
#endif
#ifndef PRINTF_OUT
#define PRINTF_OUT(...) fprintf(stdout,__VA_ARGS__)
#endif
#ifndef FLUSH_OUT
#define FLUSH_OUT fflush(stdout)
#endif
#ifndef PRINTF_ERR
#define PRINTF_ERR(...) fprintf(stderr,__VA_ARGS__)
#endif
#ifndef PERROR
#include <errno.h>
#define PERROR(x) PRINTF_ERR("%s: %s\n",x,strerror(errno))
#endif
#ifndef FLUSH_ALL
#define FLUSH_ALL fflush(NULL)
#endif
#endif /* !__COMMONINCLUDE_H */
+454
View File
@@ -0,0 +1,454 @@
/*
* unless noted otherwise: Copyright (C) 2003-2010,2019,2020,2021 Klaus Michael Indlekofer. All rights reserved.
*
* m.indlekofer@gmx.de
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "commoninclude.h"
#ifdef _VISUALCPP
/* bcopy, bzero */
/* (c) 2003, 2004 by K. M. Indlekofer */
void
bcopy(const void *src,void *dst,size_t len)
{
char *cp1,*cp2;
cp1=(char *)src;
cp2=(char *)dst;
/* XXX no check for NULL pointer */
while (len-->0){
*cp2=*cp1;
cp1++;
cp2++;
}
}
void
bzero(void *b,size_t len)
{
char *cp;
cp=(char *)b;
/* XXX no check for NULL pointer */
while (len-->0){
*cp=0;
cp++;
}
}
/* strcasecmp */
/*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* This array is designed for mapping upper and lower case letter
* together for a case independent comparison. The mappings are
* based upon ascii character sequences.
*/
static const u_char charmap[] = {
0000, 0001, 0002, 0003, 0004, 0005, 0006, 0007,
0010, 0011, 0012, 0013, 0014, 0015, 0016, 0017,
0020, 0021, 0022, 0023, 0024, 0025, 0026, 0027,
0030, 0031, 0032, 0033, 0034, 0035, 0036, 0037,
0040, 0041, 0042, 0043, 0044, 0045, 0046, 0047,
0050, 0051, 0052, 0053, 0054, 0055, 0056, 0057,
0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067,
0070, 0071, 0072, 0073, 0074, 0075, 0076, 0077,
0100, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
0170, 0171, 0172, 0133, 0134, 0135, 0136, 0137,
0140, 0141, 0142, 0143, 0144, 0145, 0146, 0147,
0150, 0151, 0152, 0153, 0154, 0155, 0156, 0157,
0160, 0161, 0162, 0163, 0164, 0165, 0166, 0167,
0170, 0171, 0172, 0173, 0174, 0175, 0176, 0177,
0200, 0201, 0202, 0203, 0204, 0205, 0206, 0207,
0210, 0211, 0212, 0213, 0214, 0215, 0216, 0217,
0220, 0221, 0222, 0223, 0224, 0225, 0226, 0227,
0230, 0231, 0232, 0233, 0234, 0235, 0236, 0237,
0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377
};
int
strcasecmp(const char *s1, const char *s2) {
const u_char *cm = charmap,
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
while (cm[*us1] == cm[*us2++])
if (*us1++ == '\0')
return (0);
return (cm[*us1] - cm[*--us2]);
}
int
strncasecmp(const char *s1, const char *s2, size_t n) {
if (n != 0) {
const u_char *cm = charmap,
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
do {
if (cm[*us1] != cm[*us2++])
return (cm[*us1] - cm[*--us2]);
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return (0);
}
/* getopt */
/*
* getopt.c --
*
* Standard UNIX getopt function. Code is from BSD.
*
* Copyright (c) 1987-2002 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* A. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* B. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* C. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* modified by K.M.Indlekofer */
/* #if !defined(lint)
* static char sccsid[] = "@(#)getopt.c 8.2 (Berkeley) 4/2/94";
* #endif
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* declarations to provide consistent linkage */
extern char *optarg;
extern int optind;
extern int opterr;
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(nargc, nargv, ostr)
int nargc;
char * const *nargv;
const char *ostr;
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (EOF);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (EOF);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means EOF.
*/
if (optopt == (int)'-')
return (EOF);
if (!*place)
++optind;
#ifdef GETOPT_PRINTF_ERR
if (opterr && *ostr != ':')
(void)GETOPT_PRINTF_ERR(
"%s: illegal option -- %c\n", __FILE__, optopt);
#endif
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
#ifdef GETOPT_PRINTF_ERR
if (opterr)
(void)GETOPT_PRINTF_ERR(
"%s: option requires an argument -- %c\n",
__FILE__, optopt);
#endif
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}
#else /* !_VISUALCPP */
/* e.g. UNIX-like systems or cygwin */
#ifndef NOT_MYLSEEK64
/* own 64bit version of lseek */
OFF64_T
mylseek64(int filedes,OFF64_T offset,int whence)
{
OFF64_T remain;
OFF64_T chunk;
OFF64_T ret;
OFF64_T c;
int whence2;
ret=0;
remain=offset;
for (c=0;;c++){
chunk=remain;
if (chunk>0x40000000){ /* XXX */
chunk=0x40000000;
}else if (chunk<-0x40000000){
chunk=-0x40000000;
}
if ((whence==SEEK_SET)&&(c>0)){ /* SEEK_SET and not first chunk? */
whence2=SEEK_CUR;
}else{
whence2=whence;
}
#if defined(DEBUGIO)&&defined(MYLSEEK64_PRINTF)
MYLSEEK64_PRINTF("c:%08x%08x chunk:%08x\n",(u_int)(c>>32),(u_int)c,(u_int)chunk);
#endif
if (LSEEK(filedes,(OFF_T)chunk,whence2)<0){
ret=-1;
break;
}
if (remain==0){
break;
}
remain-=chunk;
}
if (ret<0){
return ret;
}else{
return offset-remain;
}
}
#endif /* !NOT_MYLSEEK64 */
#endif /* !_VISUALCPP */
#ifdef USE_MY_STRHEX_TO_UINT64
U_INT64
my_strhex_to_uint64(char *s)
{
u_int l;
u_int u1,u2;
U_INT64 u;
static char s2[8+1]; /* XXX max. 8 upper digits */
if (s==NULL){
return 0;
}
l=(u_int)strlen(s);
if (l==0){
return 0;
}
/* XXX can handle max. 16 digits */
if (l>8){
#if 1
sscanf(s+l-8,"%x",&u1); /* lower 8 digits */
#else
u1=strtol(s+l-8,NULL,16); /* lower 8 digits */
#endif
strncpy(s2,
s+((l>16)?(l-16):0),
(((l-8)<=8)?(l-8):8)); /* XXX max. 8 upper digits */
s2[8]='\0';
#if 1
sscanf(s2,"%x",&u2); /* upper digits */
#else
u2=strtol(s2,NULL,16); /* upper digits */
#endif
u=(((U_INT64)u2)<<32)|((U_INT64)u1);
}else{
#if 1
sscanf(s,"%x",&u1);
u=(U_INT64)u1;
#else
u=(U_INT64)strtol(s,NULL,16);
#endif
}
return u;
}
#endif
#ifdef USE_MY_STRDEC_TO_UINT64
U_INT64
my_strdec_to_uint64(char *s)
{
u_int l;
u_int u1,u2;
U_INT64 u;
static char s2[9+1]; /* XXX max. 9 upper digits */
if (s==NULL){
return 0;
}
l=(u_int)strlen(s);
if (l==0){
return 0;
}
/* XXX can handle max. 18 digits */
if (l>9){
#if 1
sscanf(s+l-9,"%u",&u1); /* lower 9 digits */
#else
u1=strtol(s+l-9,NULL,10); /* lower 9 digits */
#endif
strncpy(s2,
s+((l>18)?(l-18):0),
(((l-9)<=9)?(l-9):9)); /* XXX max. 9 upper digits */
s2[9]='\0';
#if 1
sscanf(s2,"%u",&u2); /* upper digits */
#else
u2=strtol(s2,NULL,10); /* upper digits */
#endif
u=((U_INT64)u2)*((U_INT64)1000000000)+((U_INT64)u1);
}else{
#if 1
sscanf(s,"%u",&u1);
u=(U_INT64)u1;
#else
u=(U_INT64)strtol(s,NULL,10);
#endif
}
return u;
}
#endif
/* EOF */
+299
View File
@@ -0,0 +1,299 @@
// fdrawcmd.sys 1.0.1.11
//
// Low-level floppy filter, by Simon Owen
//
// http://simonowen.com/fdrawcmd/
#ifndef FDRAWCMD_H
#define FDRAWCMD_H
#ifndef CTL_CODE
#include <winioctl.h>
#endif
#define FDRAWCMD_VERSION 0x0100010b // Compile-time version, for structures and definitions below
// Must be checked with run-time driver for compatibility
#define FD_CTL_CODE(i,m) CTL_CODE(FILE_DEVICE_UNKNOWN, i, m, FILE_READ_DATA|FILE_WRITE_DATA)
// If you're not using C/C++, use the IOCTL values below
#define IOCTL_FDRAWCMD_GET_VERSION FD_CTL_CODE(0x888, METHOD_BUFFERED) // 0x0022e220
#define IOCTL_FDCMD_READ_TRACK FD_CTL_CODE(0x802, METHOD_OUT_DIRECT) // 0x0022e00a
#define IOCTL_FDCMD_SPECIFY FD_CTL_CODE(0x803, METHOD_BUFFERED) // 0x0022e00c
#define IOCTL_FDCMD_SENSE_DRIVE_STATUS FD_CTL_CODE(0x804, METHOD_BUFFERED) // 0x0022e010
#define IOCTL_FDCMD_WRITE_DATA FD_CTL_CODE(0x805, METHOD_IN_DIRECT) // 0x0022e015
#define IOCTL_FDCMD_READ_DATA FD_CTL_CODE(0x806, METHOD_OUT_DIRECT) // 0x0022e01a
#define IOCTL_FDCMD_RECALIBRATE FD_CTL_CODE(0x807, METHOD_BUFFERED) // 0x0022e01c
#define IOCTL_FDCMD_SENSE_INT_STATUS FD_CTL_CODE(0x808, METHOD_BUFFERED) // 0x0022e020 // added in 1.0.0.22
#define IOCTL_FDCMD_WRITE_DELETED_DATA FD_CTL_CODE(0x809, METHOD_IN_DIRECT) // 0x0022e025
#define IOCTL_FDCMD_READ_ID FD_CTL_CODE(0x80a, METHOD_BUFFERED) // 0x0022e028
#define IOCTL_FDCMD_READ_DELETED_DATA FD_CTL_CODE(0x80c, METHOD_OUT_DIRECT) // 0x0022e032
#define IOCTL_FDCMD_FORMAT_TRACK FD_CTL_CODE(0x80d, METHOD_BUFFERED) // 0x0022e034
#define IOCTL_FDCMD_DUMPREG FD_CTL_CODE(0x80e, METHOD_BUFFERED) // 0x0022e038
#define IOCTL_FDCMD_SEEK FD_CTL_CODE(0x80f, METHOD_BUFFERED) // 0x0022e03c
#define IOCTL_FDCMD_VERSION FD_CTL_CODE(0x810, METHOD_BUFFERED) // 0x0022e040
#define IOCTL_FDCMD_SCAN_EQUAL FD_CTL_CODE(0x811, METHOD_IN_DIRECT) // 0x0022e045 (not implemented yet)
#define IOCTL_FDCMD_PERPENDICULAR_MODE FD_CTL_CODE(0x812, METHOD_BUFFERED) // 0x0022e048
#define IOCTL_FDCMD_CONFIGURE FD_CTL_CODE(0x813, METHOD_BUFFERED) // 0x0022e04c
#define IOCTL_FDCMD_LOCK FD_CTL_CODE(0x814, METHOD_BUFFERED) // 0x0022e050
#define IOCTL_FDCMD_VERIFY FD_CTL_CODE(0x816, METHOD_BUFFERED) // 0x0022e058
#define IOCTL_FDCMD_POWERDOWN_MODE FD_CTL_CODE(0x817, METHOD_BUFFERED) // 0x0022e05c (not implemented yet)
#define IOCTL_FDCMD_PART_ID FD_CTL_CODE(0x818, METHOD_BUFFERED) // 0x0022e060
#define IOCTL_FDCMD_SCAN_LOW_OR_EQUAL FD_CTL_CODE(0x819, METHOD_IN_DIRECT) // 0x0022e065 (not implemented yet)
#define IOCTL_FDCMD_SCAN_HIGH_OR_EQUAL FD_CTL_CODE(0x81d, METHOD_IN_DIRECT) // 0x0022e075 (not implemented yet)
#define IOCTL_FDCMD_SAVE FD_CTL_CODE(0x82e, METHOD_BUFFERED) // 0x0022e0b8 (not implemented yet)
#define IOCTL_FDCMD_OPTION FD_CTL_CODE(0x833, METHOD_BUFFERED) // 0x0022e0cc (not implemented yet)
#define IOCTL_FDCMD_RESTORE FD_CTL_CODE(0x84e, METHOD_BUFFERED) // 0x0022e138 (not implemented yet)
#define IOCTL_FDCMD_DRIVE_SPEC_CMD FD_CTL_CODE(0x88e, METHOD_BUFFERED) // 0x0022e238 (not implemented yet)
#define IOCTL_FDCMD_RELATIVE_SEEK FD_CTL_CODE(0x88f, METHOD_BUFFERED) // 0x0022e23c
#define IOCTL_FDCMD_FORMAT_AND_WRITE FD_CTL_CODE(0x8ef, METHOD_BUFFERED) // 0x0022e3bc // added in 1.0.1.10
#define IOCTL_FD_SCAN_TRACK FD_CTL_CODE(0x900, METHOD_BUFFERED) // 0x0022e400
#define IOCTL_FD_GET_RESULT FD_CTL_CODE(0x901, METHOD_BUFFERED) // 0x0022e404
#define IOCTL_FD_RESET FD_CTL_CODE(0x902, METHOD_BUFFERED) // 0x0022e408
#define IOCTL_FD_SET_MOTOR_TIMEOUT FD_CTL_CODE(0x903, METHOD_BUFFERED) // 0x0022e40c
#define IOCTL_FD_SET_DATA_RATE FD_CTL_CODE(0x904, METHOD_BUFFERED) // 0x0022e410
#define IOCTL_FD_GET_FDC_INFO FD_CTL_CODE(0x905, METHOD_BUFFERED) // 0x0022e414
#define IOCTL_FD_GET_REMAIN_COUNT FD_CTL_CODE(0x906, METHOD_BUFFERED) // 0x0022e418 // added in 1.0.0.22
#define IOCTL_FD_SET_DISK_CHECK FD_CTL_CODE(0x908, METHOD_BUFFERED) // 0x0022e420
#define IOCTL_FD_SET_SHORT_WRITE FD_CTL_CODE(0x909, METHOD_BUFFERED) // 0x0022e424 // added in 1.0.0.22
#define IOCTL_FD_SET_SECTOR_OFFSET FD_CTL_CODE(0x90a, METHOD_BUFFERED) // 0x0022e428 // added in 1.0.0.22
#define IOCTL_FD_SET_HEAD_SETTLE_TIME FD_CTL_CODE(0x90b, METHOD_BUFFERED) // 0x0022e42c // added in 1.0.0.22
#define IOCTL_FD_LOCK_FDC FD_CTL_CODE(0x910, METHOD_BUFFERED) // 0x0022e440 // obsolete from 1.0.1.0
#define IOCTL_FD_UNLOCK_FDC FD_CTL_CODE(0x911, METHOD_BUFFERED) // 0x0022e444 // obsolete from 1.0.1.0
#define IOCTL_FD_MOTOR_ON FD_CTL_CODE(0x912, METHOD_BUFFERED) // 0x0022e448
#define IOCTL_FD_MOTOR_OFF FD_CTL_CODE(0x913, METHOD_BUFFERED) // 0x0022e44c
#define IOCTL_FD_WAIT_INDEX FD_CTL_CODE(0x914, METHOD_BUFFERED) // 0x0022e450 // added in 1.0.0.22
#define IOCTL_FD_TIMED_SCAN_TRACK FD_CTL_CODE(0x915, METHOD_BUFFERED) // 0x0022e454 // added in 1.0.0.22
#define IOCTL_FD_RAW_READ_TRACK FD_CTL_CODE(0x916, METHOD_OUT_DIRECT) // 0x0022e45a // added in 1.0.1.4
#define IOCTL_FD_CHECK_DISK FD_CTL_CODE(0x917, METHOD_BUFFERED) // 0x0022e45c // added in 1.0.1.10
#define IOCTL_FD_GET_TRACK_TIME FD_CTL_CODE(0x918, METHOD_BUFFERED) // 0x0022e460 // added in 1.0.1.10
///////////////////////////////////////////////////////////////////////////////
// Command flags: multi-track, MFM, sector skip, relative seek direction, verify enable count
#define FD_OPTION_MT 0x80
#define FD_OPTION_MFM 0x40
#define FD_OPTION_SK 0x20
#define FD_OPTION_DIR 0x40
#define FD_OPTION_EC 0x01
#define FD_OPTION_FM 0x00
#define FD_ENCODING_MASK FD_OPTION_MFM
// Controller data rates, for use with IOCTL_FD_SET_DATA_RATE
#define FD_RATE_MASK 3
#define FD_RATE_500K 0
#define FD_RATE_300K 1
#define FD_RATE_250K 2
#define FD_RATE_1M 3
// FD_FDC_INFO controller types
#define FDC_TYPE_UNKNOWN 0
#define FDC_TYPE_UNKNOWN2 1
#define FDC_TYPE_NORMAL 2
#define FDC_TYPE_ENHANCED 3
#define FDC_TYPE_82077 4
#define FDC_TYPE_82077AA 5
#define FDC_TYPE_82078_44 6
#define FDC_TYPE_82078_64 7
#define FDC_TYPE_NATIONAL 8
// Bits representing supported data rates, for the FD_FDC_INFO structure below
#define FDC_SPEED_250K 0x01
#define FDC_SPEED_300K 0x02
#define FDC_SPEED_500K 0x04
#define FDC_SPEED_1M 0x08
#define FDC_SPEED_2M 0x10
#pragma pack(push,1)
#pragma warning(push)
#pragma warning(disable:4200) // allow zero-sized arrays
typedef struct tagFD_ID_HEADER
{
BYTE cyl, head, sector, size;
}
FD_ID_HEADER, *PFD_ID_HEADER;
typedef struct tagFD_SEEK_PARAMS
{
BYTE cyl;
BYTE head;
}
FD_SEEK_PARAMS, *PFD_SEEK_PARAMS;
typedef struct tagFD_RELATIVE_SEEK_PARAMS
{
BYTE flags; // DIR
BYTE head;
BYTE offset;
}
FD_RELATIVE_SEEK_PARAMS, *PFD_RELATIVE_SEEK_PARAMS;
typedef struct tagFD_READ_WRITE_PARAMS
{
BYTE flags; // MT MFM SK
BYTE phead;
BYTE cyl, head, sector, size;
BYTE eot, gap, datalen;
}
FD_READ_WRITE_PARAMS, *PFD_READ_WRITE_PARAMS;
typedef struct tagFD_CMD_RESULT
{
BYTE st0, st1, st2;
BYTE cyl, head, sector, size;
}
FD_CMD_RESULT, *PFD_CMD_RESULT;
typedef struct tagFD_FORMAT_PARAMS
{
BYTE flags; // MFM
BYTE phead;
BYTE size, sectors, gap, fill;
FD_ID_HEADER Header[];
}
FD_FORMAT_PARAMS, *PFD_FORMAT_PARAMS;
typedef struct tagFD_READ_ID_PARAMS
{
BYTE flags; // MFM
BYTE head;
}
FD_READ_ID_PARAMS, *PFD_READ_ID_PARAMS;
typedef struct tagFD_CONFIGURE_PARAMS
{
BYTE eis_efifo_poll_fifothr; // b6 = enable implied seek, b5 = enable fifo, b4 = poll disable, b3-b0 = fifo threshold
BYTE pretrk; // precompensation start track
}
FD_CONFIGURE_PARAMS, *PFD_CONFIGURE_PARAMS;
typedef struct tagFD_SPECIFY_PARAMS
{
BYTE srt_hut; // b7-b4 = step rate, b3-b0 = head unload time
BYTE hlt_nd; // b7-b1 = head load time, b0 = non-DMA flag (unsupported)
}
FD_SPECIFY_PARAMS, *PFD_SPECIFY_PARAMS;
typedef struct tagFD_SENSE_PARAMS
{
BYTE head;
}
FD_SENSE_PARAMS, *PFD_SENSE_PARAMS;
typedef struct tagFD_DRIVE_STATUS
{
BYTE st3;
}
FD_DRIVE_STATUS, *PFD_DRIVE_STATUS;
typedef struct tagFD_INTERRUPT_STATUS
{
BYTE st0; // status register 0
BYTE pcn; // present cylinder number
}
FD_INTERRUPT_STATUS, *PFD_INTERRUPT_STATUS;
typedef struct tagFD_PERPENDICULAR_PARAMS
{
BYTE ow_ds_gap_wgate; // b7 = OW, b6 = 0, b5-b2 = drive select, b1 = gap2, b0 = write gate pre-erase loads
}
FD_PERPENDICULAR_PARAMS, *PFD_PERPENDICULAR_PARAMS;
typedef struct tagFD_LOCK_PARAMS
{
BYTE lock; // b7 = lock
}
FD_LOCK_PARAMS, *PFD_LOCK_PARAMS;
typedef struct tagFD_LOCK_RESULT
{
BYTE lock; // b4 = lock
}
FD_LOCK_RESULT, *PFD_LOCK_RESULT;
typedef struct tagFD_DUMPREG_RESULT
{
BYTE pcn0, pcn1, pcn2, pcn3; // present cylinder numbers
BYTE srt_hut; // b7-4 = step rate, b3-0 = head unload time
BYTE hlt_nd; // b7-1 = head load time, b0 = non-dma mode
BYTE sceot; // sector count / end of track
BYTE lock_d0123_gap_wgate; // b7 = setting lock, b5-2 = drive selects, b1 = gap 2 (perpendicular), b0 = write gate
BYTE eis_efifo_poll_fifothr; // b6 = implied seeks, b5 = fifo enable, b4 = poll disable, b3-0 = fifo threshold
BYTE pretrk; // pre-comp start track
}
FD_DUMPREG_RESULT, *PFD_DUMPREG_RESULT;
typedef struct tagFD_SECTOR_OFFSET_PARAMS
{
BYTE sectors; // number of sectors to skip after index
}
FD_SECTOR_OFFSET_PARAMS, *PFD_SECTOR_OFFSET_PARAMS;
typedef struct tagFD_SHORT_WRITE_PARAMS
{
DWORD length; // length to write before interrupting
DWORD finetune; // finetune delay in microseconds
}
FD_SHORT_WRITE_PARAMS, *PFD_SHORT_WRITE_PARAMS;
typedef struct tagFD_SCAN_PARAMS
{
BYTE flags; // MFM
BYTE head;
}
FD_SCAN_PARAMS, *PFD_SCAN_PARAMS;
typedef struct tagFD_SCAN_RESULT
{
BYTE count; // count of returned headers
FD_ID_HEADER Header[]; // array of 'count' id fields
}
FD_SCAN_RESULT, *PFD_SCAN_RESULT;
typedef struct tagFD_TIMED_ID_HEADER
{
DWORD reltime; // time relative to index (in microseconds)
BYTE cyl, head, sector, size;
}
FD_TIMED_ID_HEADER, *PFD_TIMED_ID_HEADER;
typedef struct tagFD_TIMED_SCAN_RESULT
{
BYTE count; // count of returned headers
BYTE firstseen; // offset of first sector detected
DWORD tracktime; // total time for track (in microseconds)
FD_TIMED_ID_HEADER Header[]; // array of 'count' id fields
}
FD_TIMED_SCAN_RESULT, *PFD_TIMED_SCAN_RESULT;
typedef struct tagFD_FDC_INFO
{
BYTE ControllerType; // FDC_TYPE_*
BYTE SpeedsAvailable; // FDC_SPEED_* values ORed together
BYTE BusType;
DWORD BusNumber;
DWORD ControllerNumber;
DWORD PeripheralNumber;
}
FD_FDC_INFO, *PFD_FDC_INFO;
typedef struct tagFD_RAW_READ_PARAMS
{
BYTE flags; // MFM
BYTE head, size;
}
FD_RAW_READ_PARAMS, *PFD_RAW_READ_PARAMS;
#pragma warning(pop)
#pragma pack(pop)
#endif // FDRAWCMD_H
+339
View File
@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.