---
title: "R2camtrapdp: 音声（音響）データ（日本語）"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{R2camtrapdp acoustic (audio) data (Japanese)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(R2camtrapdp)
```

# 概要

音声（音響）録音は Camtrap DP の **bioacoustics フレーバー**で扱います。音声データは
**メディアベース**（`observationLevel = "media"`）で、各観察はメディアファイル
（`mediaID`）を参照します。カメラトラップとの差分は音響スキーマから自動的に読み取られ、
主な点は次のとおりです。

* **deployments** は `camera*` の代わりに **`device*`** 列（`deviceID`,
  `deviceModel` など）＋ `elevation`, `devicePlatform`, `recordingSchedule`,
  `locationType`。
* **media** は `duration`, `samplingFrequency`, `bitDepth`, `gain`, `channels`
  を追加。`fileMediatype` は `audio/wav` 等の音声タイプ。
* **observations** は `frequencyLow`, `frequencyHigh` を追加。`cameraSetupType`
  は `deviceSetupType` に。
* **日時書式はテーブルごとに異なる**: `deployments` は `%Y-%m-%dT%H:%M:%S%z`
  （小数秒なし）、`media` / `observations` の時刻は小数秒付き
  `%Y-%m-%dT%H:%M:%S.%f%z`。
* `project$captureMethod` の音声向けの値は `activityDetection` / `continuous` /
  `recordingSchedule`（`timeLapse` は不可）。

> **ヒント — 日時は `POSIXct` で渡す。** そうすれば各テーブルの書式へ正しく整形され
> （オフセット `+0900`、必要な箇所には小数秒 `.000`）。`"2026/6/12 12:00:00"` の
> ような生文字列はそのまま書き出され検証に失敗します。

この例では、野帳が **設置情報の野帳**と**観察情報の野帳**の2つだけあり、観察野帳に
音声の**ファイル名**が記録されている前提で、そこから `media` を作成します。

# データ

```{r}
data("Adep")   # 設置情報の野帳（デバイス設置1件＝1行）
data("Aobs")   # 観察情報の野帳（観察1件＝1行。`filename` を持つ）
str(Adep, vec.len = 2)
str(Aobs, vec.len = 2)
```

`Adep` は `deploymentID`、座標、`startDate`/`startTime`、`endDate`/`endTime`、
`deviceID`、`deviceModel`、録音設定（`samplingFrequency`, `bitDepth`,
`channels`）、`setupBy` を持ちます。`Aobs` は `deploymentID`、`filename`、
`date`/`time`、`duration`、分類（`class`/`genus`/`species`）、`individualCount`、
`frequencyLow`/`frequencyHigh`、`eventStart`/`eventEnd` を持ちます。この例データでは、
座標は伊豆半島内、`individualCount` は `NA`（音響では個体数を数えない）、
`frequencyLow`/`frequencyHigh` は文献に基づく概算値です。

# 1. bioacoustics フレーバーを指定

```{r, eval = FALSE}
ba <- "https://raw.githubusercontent.com/camera-traps/bioacoustics/main/camtrap-dp/1.0.2/%s"

dp <- R6_CamtrapDP$new(version = "1.0.2",
  title = "音響調査の例", description = "AudioMoth 録音",
  id = "https://example.org/dataset/acoustic-1")

dp$set_properties(
  version     = "1.0.2",
  profile     = sprintf(ba, "camtrap-dp-profile-acoustic.json"),
  schema_urls = list(
    deployments  = sprintf(ba, "deployments-table-schema-acoustic.json"),
    media        = sprintf(ba, "media-table-schema-acoustic.json"),
    observations = sprintf(ba, "observations-table-schema-acoustic.json")))
```

# 2. deployments（設置野帳から）

`Adep` から deployments を作成します。日付列と時刻列を `POSIXct` に結合して渡すと、
正しい日時書式で書き出されます。

```{r}
deployments <- data.frame(
  deploymentID    = Adep$deploymentID,
  latitude        = Adep$latitude,
  longitude       = Adep$longitude,
  locationID      = Adep$locationID,
  deploymentStart = as.POSIXct(paste(Adep$startDate, Adep$startTime), tz = "Asia/Tokyo"),
  deploymentEnd   = as.POSIXct(paste(Adep$endDate,   Adep$endTime),   tz = "Asia/Tokyo"),
  deviceID        = Adep$deviceID,
  deviceModel     = Adep$deviceModel,
  setupBy         = Adep$setupBy,
  stringsAsFactors = FALSE)
```
```{r, eval = FALSE}
dp$set_deployments(deployments)
```

# 3. media（観察野帳のファイル名から生成）

メディア用の野帳は無いので、`Aobs` のユニークな `filename`（音声ファイル1件＝1行）から
`media` を作り、録音設定は `Adep` から結合します。

```{r}
files <- Aobs[!duplicated(Aobs$filename), ]   # 音声ファイルごとに1行

media <- data.frame(
  mediaID       = files$filename,             # ファイル名をメディア識別子に
  deploymentID  = files$deploymentID,
  timestamp     = as.POSIXct(paste(files$date, files$time), tz = "Asia/Tokyo"),
  filePath      = file.path("audio", files$filename),
  filePublic    = TRUE,
  fileMediatype = paste0("audio/", tolower(tools::file_ext(files$filename))),  # "audio/wav"
  duration      = files$duration,
  stringsAsFactors = FALSE)

# 録音設定（samplingFrequency / bitDepth / channels）を Adep から付与
media <- merge(media, Adep[, c("deploymentID", "samplingFrequency", "bitDepth", "channels")],
               by = "deploymentID", all.x = TRUE)
head(media)
```
```{r, eval = FALSE}
dp$set_media(media)
```

`timestamp` は `POSIXct` なので、音響 `media` の書式に合わせて小数秒付き
（例 `2026-06-12T06:00:00.000+0900`）で自動的に書き出されます。

# 4. observations（観察野帳から）

```{r}
observations <- data.frame(
  observationID    = paste(Aobs$deploymentID, Aobs$eventID, Aobs$obsID, sep = "_"),
  deploymentID     = Aobs$deploymentID,
  mediaID          = Aobs$filename,           # media へのリンク（mediaID = filename）
  eventStart       = as.POSIXct(Aobs$eventStart, tz = "Asia/Tokyo"),
  eventEnd         = as.POSIXct(Aobs$eventEnd,   tz = "Asia/Tokyo"),
  observationLevel = "media",
  observationType  = ifelse(Aobs$object == "none", "blank",
                     ifelse(Aobs$object == "hito", "human", "animal")),
  scientificName   = ifelse(is.na(Aobs$genus), Aobs$class, paste(Aobs$genus, Aobs$species)),
  count            = Aobs$individualCount,    # 音響では個体数を数えないため NA
  frequencyLow     = Aobs$frequencyLow,
  frequencyHigh    = Aobs$frequencyHigh,
  stringsAsFactors = FALSE)
```
```{r, eval = FALSE}
dp$set_observations(observations)
```

# 5. メタデータ・リレーション・書き出し・検証

```{r, eval = FALSE}
dp$add_contributors(data.frame(title = "Jane Doe", role = "contact",
                               organization = "NIES", stringsAsFactors = FALSE))
dp$add_license(name = "CC0-1.0",   scope = "data")
dp$add_license(name = "CC-BY-4.0", scope = "media")
dp$set_project(title = "音響調査", samplingDesign = "systematicRandom",
               captureMethod = "recordingSchedule", individualAnimals = FALSE,
               observationLevel = "media")
dp$set_st()
# dp$set_taxon()   # GBIF/ITIS/NCBI から taxonID。taxadb パッケージ＋ネット接続が必要

dp$check_relations()   # PK/FK。キー列が欠損なら datapackage$data$... を指す警告を出す

path <- file.path(tempdir(), "acoustic-package")
dp$out_camtrapdp(write = TRUE, directory = path)

issues <- dp$validate_frictionless(directory = path, python = "python")  # 要 pip install frictionless
ctdp_is_valid(issues)
```

既にディスク上にあるパッケージを**上書きせず検証だけ**する場合:

```{r, eval = FALSE}
ctdp_validate_frictionless("path/to/existing/acoustic-package", python = "python")
```

# 6. 音響スキーマの要件確認

```{r, eval = FALSE}
ba <- "https://raw.githubusercontent.com/camera-traps/bioacoustics/main/camtrap-dp/1.0.2/%s"
acoustic_media <- TableSchema$new(
  "media", version = "1.0.2",
  url_template = sprintf(ba, "media-table-schema-acoustic.json"))

acoustic_media$field_names()
acoustic_media$requirements()                 # 各列の type / format / required / enum
acoustic_media$field("timestamp")$format      # "%Y-%m-%dT%H:%M:%S.%f%z"
```
