@ghoran/audio 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +150 -3
- package/package.json +68 -3
package/README.md
CHANGED
|
@@ -1,3 +1,150 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# @ghoran/audio
|
|
2
|
+
|
|
3
|
+
پروفایلهای کمحجم و Tree-shakable برای هماهنگی بلندی تلاوت و ترجمهٔ صوتی قرآن؛ بدون وابستگی اجرایی، دریافت صوت، Decode، تحلیل لحظهای یا کنترل پلیر.
|
|
4
|
+
|
|
5
|
+
## نسخهٔ مرجع فعلی
|
|
6
|
+
|
|
7
|
+
این snapshot شامل ۸۱٬۰۶۸ فایل قابل Decode و دارای Gain است؛ ۱۰ فایل خراب و یک فایل بسیار کوتاه با ۱۱ نسخهٔ جایگزین پذیرفتهشده توسط کاربر رفع شدهاند. سابقهٔ قبلی حفظ شده است. این پذیرش، تأیید مستقل شنیداریِ متن یا مرزها نیست.
|
|
8
|
+
|
|
9
|
+
**انتشار این ۱۱ نسخه در URLهای اصلی هنوز تأیید نشده است.** `audioDataset.pendingPublicationFiles` جمع آنها و `profile.metadata.pendingPublicationFiles` تعداد هر منبع را نشان میدهد. تا جایگزینی بایتهای CDN و پاکشدن cache قدیمی، Gain جدید فقط برای همان فایل مرجع جدید معتبر است. مسیر `/verify` هش قدیمی را رد میکند. نبود Gain در snapshot فعلی صفر است، ولی API همچنان برای نسخهٔ نامعتبر/ناشناخته یا هش نامنطبق `null` را حفظ میکند. هشدارهای آماری باقیمانده مستقل از این اصلاحها هستند.
|
|
10
|
+
|
|
11
|
+
## شروع سریع
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { parhizgar, ansarian } from '@ghoran/audio'
|
|
15
|
+
|
|
16
|
+
const ayahIndex = 261 // بقره، آیهٔ ۲۵۵؛ همان اندیس متن و Ayah.index
|
|
17
|
+
const gain = parhizgar.getGain(ayahIndex) // ضریب خطی آماده، با حفاظت Peak
|
|
18
|
+
const translationGain = ansarian.getGain(ayahIndex)
|
|
19
|
+
|
|
20
|
+
if (gain !== null) {
|
|
21
|
+
// مقدار آماده را به کنترل Gain پلیر خود بدهید.
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
هر منبع فقط متادیتا و استثناهای خودش را دارد. import نامدارِ بالا توسط bundler قابل Tree Shaking است. برای مرزبندی صریحتر، ورودی مستقل نیز وجود دارد:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import parhizgar from '@ghoran/audio/sources/parhizgar'
|
|
29
|
+
import ansarian from '@ghoran/audio/sources/ansarian'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
ورودی اصلی هیچ catalog سراسری، manifest هش، loader پویا یا اندازهگیری پژوهشی را وارد مسیر پخش نمیکند. بیلد مصرفکنندهٔ واقعی، نبود متادیتای ۱۱ منبع دیگر، سایر سیاستها و دادهٔ SHA-256 را برای این مثال بررسی میکند. ورود namespace و استفادهٔ پویا از همهٔ exportها میتواند مانع حذف منابع شود؛ برای پروژه با منابع ثابت، named import یا subpath مناسب است.
|
|
33
|
+
|
|
34
|
+
## API هر منبع
|
|
35
|
+
|
|
36
|
+
| API | خروجی |
|
|
37
|
+
| -------------------------------------- | ----------------------------------------------------------------- |
|
|
38
|
+
| `profile.getGain(ayahIndex)` | ضریب دامنهٔ نهایی یا `null` |
|
|
39
|
+
| `profile.getGainDb(ayahIndex)` | Gain نهایی برحسب dB یا `null` |
|
|
40
|
+
| `profile.getRecommendation(ayahIndex)` | وضعیت، علت نبود Gain، حفاظت Peak و نسخهٔ داده |
|
|
41
|
+
| `profile.metadata` | نام، نوع، baseline، تعداد اندازهگیری و contentRevision همان منبع |
|
|
42
|
+
| `profile.policy` | هدف، سقف Peak، حاشیه و حدود افزایش/کاهش |
|
|
43
|
+
|
|
44
|
+
تمام APIهای آیه از **اندیس صفرمبنا، از ۰ تا ۶۲۳۵** استفاده میکنند؛ دقیقاً همان اندیس آرایهٔ متن، ترجمه و `Ayah.index`. عدد یکمبنا، رشته و آبجکت آدرس پشتیبانی نمیشوند. اندیس نامعتبر `RangeError` میدهد؛ اندازهگیری نامعتبر یا ناموجود `null` میدهد. `null` را با `1` یا Gain پایه جایگزین نکنید.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
parhizgar.getGain(0) // فاتحه ۱
|
|
48
|
+
parhizgar.getGain(261) // بقره ۲۵۵
|
|
49
|
+
parhizgar.getGain(6235) // ناس ۶
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`getRecommendation` همان `ayahIndex` ورودی را برمیگرداند؛ برای تولید جزئیات Gain هیچ تبدیل سوره/آیه انجام نمیشود. دادهٔ runtime همچنان **Gain پایه + استثناهای کمتعداد** است و آرایهٔ ۶۲۳۶تایی Gain برای هر منبع نگهداری نمیشود.
|
|
53
|
+
|
|
54
|
+
### URL اختیاری
|
|
55
|
+
|
|
56
|
+
کد تبدیل اندیس به نام فایل و جدول ۱۱۴ سوره فقط از ورودی مستقل `/url` وارد میشوند؛ پروفایلها و registry متد `getUrl` ندارند. در برنامهای که URL خودش را دارد، این ورودی را import نکنید:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { getAudioUrl } from '@ghoran/audio/url'
|
|
60
|
+
|
|
61
|
+
const url = getAudioUrl(parhizgar, 261) // .../002255.mp3
|
|
62
|
+
// metadata انتخابشده از /catalog نیز پذیرفته میشود.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
این تابع دریافت فایل یا تأیید محتوای URL انجام نمیدهد. اگر آدرس سوره/آیه دارید، میتوانید با `Ayah.getByKey('2:255')!.index` از `@ghoran/entity` اندیس مشترک بگیرید؛ پکیج صوت برای Gain به آن پکیج وابسته نیست.
|
|
66
|
+
|
|
67
|
+
برای lookup با شناسهٔ منبع فقط منابع مورد استفاده را ثبت کنید:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createAudioNormalizer, parhizgar, ansarian } from '@ghoran/audio'
|
|
71
|
+
|
|
72
|
+
const audio = createAudioNormalizer({ sources: [parhizgar, ansarian] })
|
|
73
|
+
const gain = audio.getGain('parhizgar', 261)
|
|
74
|
+
const details = audio.getRecommendation('ansarian', 261)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
TypeScript شناسهها را به منابع ثبتشده محدود میکند. منبع تکراری، هدف متفاوت یا snapshot ناسازگار پذیرفته نمیشود. lookup همگام است و هیچ I/O ندارد. ضرایب خطی پس از آمادهسازی هر منبع cache میشوند؛ هیچ ضرب نمونهای توسط این کتابخانه اجرا نمیشود.
|
|
78
|
+
|
|
79
|
+
## سیاستهای دیگر؛ فقط در صورت import
|
|
80
|
+
|
|
81
|
+
ورودی پیشفرض هر منبع، سیاست **−۲۰ LUFS** است. برای −۲۳، −۱۸ و −۱۶، فقط همان منبع و سیاست را import کنید:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import parhizgar from '@ghoran/audio/targets/-23/parhizgar'
|
|
85
|
+
import ansarian from '@ghoran/audio/targets/-23/ansarian'
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
برای اپ با انتخاب پویا، loader اختیاری وجود دارد:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { loadAudioSource } from '@ghoran/audio/load'
|
|
92
|
+
|
|
93
|
+
const profile = await loadAudioSource('parhizgar', { targetLufs: -20 })
|
|
94
|
+
const gain = profile.getGain(0)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
مسیر `/load` در bundler میتواند chunkهای جداگانهٔ تمام گزینههای قابل انتخاب را **تولید** کند؛ فقط گزینهٔ درخواستشده را **بارگیری** میکند. برای حذف کامل سایر منابع از خروجی پروژه، ورودیهای ثابت را به کار ببرید. فهرست منابع برای UI انتخاب قاری، جداست:
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { audioSources } from '@ghoran/audio/catalog'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## حفاظت Peak و حفظ اصالت
|
|
104
|
+
|
|
105
|
+
سیاست فعلی Gain پایهٔ مجموعه را همراه با حفاظت True Peak اعمال میکند. اصلاح بخش ضبط و outlier استنباطی خودکار اعمال نمیشود. کل فایل یک Gain ثابت دارد؛ دامنهٔ طبیعی داخل آیه صاف نمیشود. هیچ MP3 تغییر یا دوباره Encode نشده است.
|
|
106
|
+
|
|
107
|
+
سقف True Peak برابر −۱ dBTP و حاشیهٔ اضافی ۰٫۱۵ dB است. افزایش حداکثر ۸ و کاهش حداکثر ۱۸ dB است. Gain به گامهای **۰٫۰۱ dB به سمت مقدار کمتر** تبدیل میشود؛ اختلاف از توصیهٔ دقیق کمتر از ۰٫۰۱ dB است و حفاظت Peak با عدد نهایی بررسی میشود. برای مثال Gain پایهٔ −۷٫۵۳۳ به −۷٫۵۴ تبدیل میشود. دقت ثابت، تعداد مقادیر و حجم داده را کاهش میدهد.
|
|
108
|
+
|
|
109
|
+
LUFS هدف، baseline مجموعه است؛ قرار نیست هر آیه به −۲۰ برسد. اعداد بر قرارداد پخش مونو با کپی دامنهٔ یکسان به هر دو کانال تکیه دارند. در pan-law دیگر، توصیهها نیاز به بازتولید دارند. جمع چند صوت همزمان و تقویت دیگری پس از این Gain، به headroom جدا نیاز دارد.
|
|
110
|
+
|
|
111
|
+
## تطبیق با نسخهٔ واقعی صوت
|
|
112
|
+
|
|
113
|
+
`getGain` یک lookup روی **صوت مرجع اندازهگیریشده** است؛ تغییر محتوای URL ثابت را تشخیص نمیدهد. `snapshotId` و `contentRevision` شناسهٔ نسخهاند و بهتنهایی اثبات تطابق بایتهای فایل نیستند. در `getRecommendation` مقدار `contentVerified` صریحاً `false` است.
|
|
114
|
+
|
|
115
|
+
برای مسیر سختگیرانه، فقط manifest هش همان منبع را وارد کنید و SHA-256 واقعی فایل دریافتشده را بدهید:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import parhizgar from '@ghoran/audio/sources/parhizgar'
|
|
119
|
+
import hashes from '@ghoran/audio/hashes/parhizgar'
|
|
120
|
+
import { getVerifiedAudioGain } from '@ghoran/audio/verify'
|
|
121
|
+
|
|
122
|
+
const gain = getVerifiedAudioGain(parhizgar, hashes, 261, actualAudioSha256)
|
|
123
|
+
// محتوای تغییرکرده، revision ناسازگار یا Gain ناموجود -> null
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
هش از بایتهای فایل اصلی است، نه PCM Decodeشده. محاسبهٔ هش را میتوانید یک بار در مسیر دانلود/cache انجام دهید. کتابخانه صوت را دوباره دریافت نمیکند و WebCrypto/DOM/Node API در runtime لازم ندارد. manifest هش عمداً از دادهٔ Gain بزرگتر و کاملاً اختیاری است. برای بارگیری پویا از `loadAudioContentManifest` در `/load` استفاده کنید.
|
|
127
|
+
|
|
128
|
+
## منابع و وضعیت داده
|
|
129
|
+
|
|
130
|
+
شناسهها: `parhizgar`, `ghamadi`, `husary`, `minshawy-murattal`, `minshawy-mujawwad`, `motaz`, `abdulbasit`, `almuiqly`, `jafarpour`, `ansarian`, `maleki`, `makarem-kabiri`, `fooladvand-hedayatfar`.
|
|
131
|
+
|
|
132
|
+
exportهای نامدار دوکلمهای camelCase هستند: `minshawyMurattal`, `minshawyMujawwad`, `makaremKabiri`, `fooladvandHedayatfar`. subpath همیشه شناسهٔ اصلی خطتیرهدار را دارد.
|
|
133
|
+
|
|
134
|
+
فهرست کامل ۸۱٬۰۶۸ مورد بررسی شده است؛ snapshot مرجع فعلی پس از پذیرش جایگزینها برای همهٔ موارد Gain دارد. انتشار ۱۱ جایگزین در URL اصلی همچنان تأیید نشده است. موفقیت Decode، صحت محتوای آیه یا انتساب قاری را ثابت نمیکند. ۱۱۲ URL معیقلی برخلاف پسوند mp3 محتوای PCM دارند؛ انتخاب decoder باید از روی محتوای واقعی انجام شود.
|
|
135
|
+
|
|
136
|
+
## توسعه و بازتولید
|
|
137
|
+
|
|
138
|
+
دادهٔ Measured، Inferred و Recommended کامل در پوشههای `analysis/` و `data/` **مخزن Git** و آرشیو مستقل نگهداری میشود؛ فایلهای حجیم پژوهشی در بستهٔ npm نیستند. `/profiles` ورود اختیاری پروفایلهای استنباطی است. دادهٔ خام `/data/*` از بستهٔ نصبشدنی صادر نمیشود.
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
pnpm --filter @ghoran/audio generate:runtime
|
|
142
|
+
pnpm --filter @ghoran/audio check:runtime
|
|
143
|
+
pnpm --filter @ghoran/audio build
|
|
144
|
+
pnpm test
|
|
145
|
+
pnpm check:packages
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
کامپایلر Node از snapshot متعهدشدهٔ داده، بدون Python، FFmpeg یا شبکه، ورودیهای مستقل هر منبع و سیاست را بازتولید میکند. هش ورودیها، شمار رکوردها، تطابق توصیهها، حدود Gain و سقف Peak را برای تمام ۳۲۴٬۲۷۲ ترکیب منبع/آیه/هدف بررسی میکند. اختلاف با سیاست baseline-only باعث شکست بیلد میشود؛ اصلاحهای استنباطی تأییدشدهٔ احتمالی آینده بدون تغییر صریح این قرارداد وارد runtime نمیشوند.
|
|
149
|
+
|
|
150
|
+
کد تحت MIT؛ ساختار سوره و آیه از [Tanzil Project](https://tanzil.net/docs/Quran_Metadata) است؛ snapshot و attribution کامل آن نیز در مخزن حفظ شدهاند. صوتهای اصلی داخل npm یا آرشیو تحلیل توزیع نمیشوند.
|
package/package.json
CHANGED
|
@@ -1,6 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghoran/audio",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tree-shakable Quran audio gain profiles, per-file peak protection and optional content verification",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.mjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"./catalog": {
|
|
15
|
+
"types": "./dist/catalog.d.ts",
|
|
16
|
+
"import": "./dist/catalog.mjs"
|
|
17
|
+
},
|
|
18
|
+
"./load": {
|
|
19
|
+
"types": "./dist/load.d.ts",
|
|
20
|
+
"import": "./dist/load.mjs"
|
|
21
|
+
},
|
|
22
|
+
"./verify": {
|
|
23
|
+
"types": "./dist/verify.d.ts",
|
|
24
|
+
"import": "./dist/verify.mjs"
|
|
25
|
+
},
|
|
26
|
+
"./profiles": {
|
|
27
|
+
"types": "./dist/profiles.d.ts",
|
|
28
|
+
"import": "./dist/profiles.mjs"
|
|
29
|
+
},
|
|
30
|
+
"./sources/*": {
|
|
31
|
+
"types": "./dist/sources/*.d.ts",
|
|
32
|
+
"import": "./dist/sources/*.mjs"
|
|
33
|
+
},
|
|
34
|
+
"./targets/*": {
|
|
35
|
+
"types": "./dist/targets/*.d.ts",
|
|
36
|
+
"import": "./dist/targets/*.mjs"
|
|
37
|
+
},
|
|
38
|
+
"./hashes/*": {
|
|
39
|
+
"types": "./dist/hashes/*.d.ts",
|
|
40
|
+
"import": "./dist/hashes/*.mjs"
|
|
41
|
+
},
|
|
42
|
+
"./url": {
|
|
43
|
+
"types": "./dist/url.d.ts",
|
|
44
|
+
"import": "./dist/url.mjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"sideEffects": false,
|
|
48
|
+
"files": [
|
|
49
|
+
"dist/**/*",
|
|
50
|
+
"README.md"
|
|
51
|
+
],
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/sabereen/ghoran.git",
|
|
55
|
+
"directory": "packages/audio"
|
|
56
|
+
},
|
|
57
|
+
"license": "MIT",
|
|
58
|
+
"publishConfig": {
|
|
59
|
+
"access": "public",
|
|
60
|
+
"registry": "https://registry.npmjs.org/"
|
|
61
|
+
},
|
|
62
|
+
"scripts": {
|
|
63
|
+
"build": "node scripts/generate-runtime.mjs && tsdown",
|
|
64
|
+
"analyze": "python3 analysis/scripts/analyze.py",
|
|
65
|
+
"extract": "python3 analysis/scripts/parallel_run.py run --phase full",
|
|
66
|
+
"test:analysis": "python3 -m unittest discover -s analysis/tests -v",
|
|
67
|
+
"export:data": "python3 analysis/scripts/export_package.py",
|
|
68
|
+
"generate:runtime": "node scripts/generate-runtime.mjs",
|
|
69
|
+
"check:runtime": "node scripts/generate-runtime.mjs --check"
|
|
70
|
+
}
|
|
6
71
|
}
|