데이터 관리
modernGraphTool에 표시할 측정 데이터(Phone)와 타겟 커브(Target)를 다루는 방법을 안내합니다.
데이터 목록은 data/phone_book.json으로 관리합니다. 경로를 따로 바꾸지 않았다면 측정 데이터 파일은 data/phones에, 타겟 커브 파일은 data/target 폴더에 들어갑니다.
modernGraphTool은 CrinGraph와 같은 데이터 구조를 그대로 따릅니다. 기존 CrinGraph 사용에 익숙하다면 이 페이지는 건너뛰어도 됩니다.
JSON을 직접 다루기 번거롭다면 phone_book.json 편집기로 phone_book.json을 불러오고, 편집하고, 내보낼 수 있습니다. 모든 phone 유형(단순, 상세, 변형, 샘플 세트)에 대한 설명이 함께 표시됩니다.
변환 기능도 겸합니다. 이전 형식으로 작성된 phone book을 불러와 현재 형식으로 내보낼 수 있습니다. 사용 중단된 hptfs[]를 아직 쓰고 있다면 한 번 거쳐 보세요.
데이터 폴더 구조
dist/data 폴더는 다음과 같이 구성됩니다.
data/
├── phones/ # 측정 데이터 파일 (.txt) 저장 위치
│ ├── PhoneA L.txt
│ ├── PhoneA R.txt
│ └── PhoneB.txt
├── target/ # 타겟 커브 데이터 파일 (.txt) 저장 위치
│ ├── X Target.txt
│ └── Y Target.txt
└── phone_book.json # 측정 기기 목록 및 관련 데이터 정의 파일
phones폴더 — 각 Phone의 주파수 응답 측정 파일(.txt)을 저장합니다. 파일 이름은 자유지만,phone_book.json에는 정확히 같은 이름을 적어야 합니다. 좌/우 채널이 별도 파일이라면 파일명 끝에 공백을 하나 두고L,R을 붙여 구분합니다.target폴더 — 타겟 커브 파일(.txt)을 저장합니다.config.js의INITIAL_TARGETS나TARGET_MANIFEST에 적는 이름과 정확히 일치해야 합니다.phone_book.json— 기기 목록에 표시될 제품 이름과 부가 정보(리뷰 링크, 가격 등)를 JSON 형식으로 정의합니다.
JSON 문법 기초
JSON(JavaScript Object Notation)은 데이터를 구조적으로 표현하는 텍스트 형식입니다. 몇 가지 기본 규칙만 알면 쉽게 읽고 고칠 수 있습니다.
- 데이터는 이름(Key)과 값(Value)의 쌍으로 이루어지며, 이름은 항상 따옴표로 감싼 문자열입니다.
- 값은 문자열(따옴표), 숫자(따옴표 없음), 불리언(
true/false, 따옴표 없음), 배열([·]로 감싸고 쉼표로 구분), 또는 다른 객체({·}로 감쌈)가 될 수 있습니다. - 객체 안의 각 키-값 쌍은 쉼표(
,)로 구분합니다. 마지막 쌍 뒤에는 쉼표를 붙이지 않습니다. - 배열 안의 각 요소도 쉼표(
,)로 구분합니다. 마지막 요소 뒤에도 쉼표는 없습니다.
phone_book.json 구조
phone_book.json은 하나의 큰 배열([])로 시작해서 끝납니다. 그 안에 여러 브랜드 객체({})가 들어갑니다.
각 브랜드 객체는 name 키(예: "Sennheiser", "Sony")와 phones 키로 구성됩니다.
phones 키 안에는 해당 브랜드의 모델(Phone) 정보가 담깁니다. 모델 정보는 단순 문자열로도, 객체로도 정의할 수 있습니다.
[
{
"name": "Brand A",
"suffix": "(Audio)", // Optional: Suffix for the brand name
"phones": [
"ModelX_Simple", // Simple definition: Assumes files "ModelX_Simple L.txt" and "ModelX_Simple R.txt"
{
"name": "Model Y",
"file": "BrandA ModelY", // File name (without L/R and .txt)
"suffix": ["(Setting 1)", "(Setting 2)"], // Optional: Suffixes for different versions
"reviewLink": "https://example.com/review/modely", // Optional: Review link
"price": "$199", // Optional: Price (string)
"description": "Some description about Model Y" // Optional: Extra description
}
// ... more models for Brand A
]
},
{
"name": "Brand B",
"phones": [
// ... models for Brand B
]
}
// ... more brands
]
Brand 객체 키
name(문자열, 필수) — 브랜드 이름.suffix(문자열, 선택) — 브랜드 이름 뒤에 붙어 UI에 표시되는 접미사.phones(배열, 필수) — 해당 브랜드의 모든 Phone 정보를 담는 배열. 각 모델은 단순 문자열 또는 상세 객체로 정의합니다.
Phone 정의 형태
phones 배열에는 다음 형태로 데이터를 넣을 수 있습니다.
단순 문자열 정의
단순 문자열(예: "ModelX")을 넣으면 화면에는 "ModelX"라고 표시되고, 데이터 파일은 ModelX L.txt, ModelX R.txt라고 가정합니다.
{
"name": "BrandSimple",
"phones": [
"ModelS1", // Loads `~/ModelS1 L.txt`, `~/ModelS1 R.txt`
"ModelS2" // Loads `~/ModelS2 L.txt`, `~/ModelS2 R.txt`
]
}
상세 객체 정의
더 자세한 설정이 필요하다면 Phone을 다음 키를 가진 객체로 정의합니다.
name(문자열, 필수) — 화면에 표시될 Phone 모델 이름.file(문자열, 필수) — 측정 데이터 파일의 실제 이름(L/R 접미사와.txt확장자 제외). 예를 들어 파일이MyPhone L.txt,MyPhone R.txt라면"MyPhone"으로 설정합니다.suffix(문자열, 선택) — 선택 목록의 이름 뒤에 붙는 접미사. 실제 데이터 파일 이름에도 같은 접미사가 들어 있어야 합니다(예:MyPhone (Foam Tip) L.txt).reviewScore(문자열, 선택) — 리뷰 점수."A+", 0~5 사이 숫자("3") 등 자유롭게 표기.reviewLink(문자열, 선택) — Phone 리뷰 URL.shopLink(문자열, 선택) — 상점 또는 구매 페이지 URL.price(문자열, 선택) — 가격(예:"$299","€250"). 문자열이라 통화 기호가 다른 표기도 그대로 허용됩니다.description(문자열, 선택) — Phone과 함께 표시할 자유 서술 설명. 일부 인라인 HTML 태그를 사용할 수 있습니다. 아래 서식 있는 설명 참고.links(객체 배열, 선택) — 기기를 그래프에 올렸을 때 기본 리뷰 / 상점 링크 옆에 함께 표시할 추가 링크. 아래 커스텀 링크 참고.
{
"name": "BrandDetailed",
"phones": [
{
"name": "Model D1",
"file": "ModelD1_Data",
"suffix": "Rev.2",
"reviewScore": "A+",
"reviewLink": "https://example.com/review/d1",
"shopLink": "https://example.com/shop/d1",
"price": "$299"
}
]
}
서식 있는 설명
description에는 인라인 HTML 태그를 일부 쓸 수 있어서, 설명 안에 링크나 강조를
넣을 수 있습니다.
{
"name": "Model D1",
"file": "ModelD1_Data",
"description": "동일 개체의 B&K5128 측정치는 <a href=\"https://other.example/?share=Brand%20Model%20D1\">여기</a>에서 볼 수 있습니다."
}
허용되는 태그: a, abbr, b, br, code, del, em, i, ins, kbd,
mark, s, small, span, strong, sub, sup, u, wbr.
그 외의 내용은 화면에 그려지기 전에 모두 정리됩니다.
- 모르는 태그는 태그만 제거되고 내용은 남습니다.
<div>text</div>는text로 표시되므로 내용이 조용히 사라지는 일은 없습니다. <script>,<style>,<iframe>등은 내용까지 통째로 제거됩니다.- 속성은 전부 제거됩니다. 예외는
<a>의href/title,<abbr>·<span>의title뿐입니다.onclick같은 이벤트 핸들러와style은 남지 않습니다. - 링크는
http,https,mailto,tel또는 상대 경로여야 합니다.javascript:URL은 제거되고 링크 텍스트만 일반 텍스트로 남습니다. - 링크는 새 탭에서 열립니다.
rel="external noopener noreferrer"가 자동으로 붙으므로target을 직접 쓸 필요가 없습니다. &는 그대로 써도 됩니다.B&K5128은 쓴 그대로 표시됩니다(&로 써도 동작합니다).
닫지 않은 태그는 자동으로 닫히므로, 오타 하나가 목록 전체의 레이아웃을 망가뜨리지
않습니다. 설명은 기기 항목 버튼 안에 렌더링되기 때문에 인라인 태그만 허용되며,
블록 태그(<p>, <ul> 등)는 태그만 제거됩니다.
설명이 잘려 있을 때 마우스를 올리면 나오는 툴팁에는 태그를 제거한 평문이 표시됩니다.
커스텀 링크
shopLink에는 URL을 하나만 넣을 수 있습니다. 상점 두 곳, 제조사 페이지, 측정
노트처럼 가리킬 곳이 여러 개라면 links를 쓰세요. 각 항목은 label과 url을
가진 객체입니다.
{
"name": "Model D1",
"file": "ModelD1_Data",
"links": [
{ "label": "Amazon", "url": "https://amazon.example/d1" },
{ "label": "공식 스토어", "url": "https://brand.example/shop/d1" },
{ "label": "측정 노트", "url": "/data/notes/d1.html" }
]
}
label(문자열, 필수) — 링크 텍스트. 평문으로만 표시되며 태그는 제거됩니다.url(문자열, 필수) —http,https,mailto,tel또는 사이트 기준 상대 경로. 그 외에는 무시됩니다.
링크는 적어 둔 순서대로, 기본 리뷰 / 상점 링크 뒤에 표시되며 기기를 그래프에 올린
뒤에만 나타납니다. links는 shopLink를 대체하지 않으므로 둘 중 하나만 써도 되고
둘 다 써도 됩니다.
label이나 url이 없거나 쓸 수 없는 URL인 항목은 (브라우저 콘솔에 경고를 남기고)
건너뛰며, 나머지 링크는 정상적으로 표시됩니다.
Variations (여러 데이터 파일을 하나로 묶기)
EQ 설정이나 이어팁에 따라 여러 버전의 측정값이 있다면, 이들을 하나의 이름으로 묶어 UI에 보여줄 수 있습니다.
{
"name": "BrandVariations",
"phones": [
{
"name": "Model V1", // Base name for variations
"file": ["ModelV1_Foam", "ModelV1_Silicone", "ModelV1_Hybrid"],
"suffix": ["(Foam Tip)", "(Silicone Tip)", "(Hybrid Tip)"],
"price": "$150" // Applies to all V1 variations
}
]
}
name,file,suffix배열을 함께 사용할 때name(문자열 배열, 필수) — 모든 Variation의 기본 이름이 되는 문자열 배열.file(문자열 배열, 필수) — 각 Variation의 기본 파일 이름 배열.suffix(문자열 배열, 필수) — 각 파일에 대응하는 접미사 배열. UI에는brand_name + name + suffix[i]형태로 표시됩니다.- 위 예시는 "BrandVariations Model V1 (Foam Tip)", "BrandVariations Model V1 (Silicone Tip)" 같은 항목으로 만들어집니다.
file과suffix배열 길이는 가급적 같아야 합니다. 다른 선택 키(reviewLink,price등)를 추가하면 모든 Variation에 똑같이 적용됩니다.
{
"name": "BrandPrefix",
"phones": [
{
"name": "Model P1", // Base display name
"file": ["BrandP ModelP1 (Foam Tip)", "BrandP ModelP1 (Silicone Tip)"], // Actual files would be: BrandP ModelP1 (Foam Tip) L.txt, BrandP ModelP1 (Silicone Tip) L.txt, etc.
"prefix": "BrandP ModelP1", // Common file prefix
"description": "Uses different eartips"
}
]
}
prefix로 공통 파일 접두사 사용하기
Variation 파일들이 같은 접두사를 공유하지만 뒷부분이 명확히 구분된다면 prefix를 쓸 수 있습니다.
name(문자열 배열, 필수) — 모든 Variation의 기본 이름이 되는 문자열 배열.file(문자열 배열, 필수) — 각 Variation의 기본 파일 이름 배열.prefix(문자열, 필수) — 모든 파일에 공통으로 붙는 접두사.- UI에는
brand_name + name + suffix[i]형태로 표시됩니다(예: "BrandPrefix Model P1 (Foam Tip)", "BrandPrefix Model P1 (Silicone Tip)"). - 여러 이어팁이나 이어패드를 조합한 측정, 또는 착용 위치별 측정처럼 같은 기기에 속한 데이터를 한데 묶을 때 편리합니다.
샘플 세트 (Sample Sets)
샘플 세트는 한 variant를 여러 번 측정한 것입니다. 같은 착용 상태의 반복 측정, 착용 위치를 조금씩 바꾼 스윕, 이어패드별 측정, 여러 장비에서 측정한 같은 기기 등이 여기에 해당합니다. modernGraphTool은 세트를 세 가지 방식으로 그릴 수 있고, 이들은 자유롭게 조합됩니다.
| 토큰 | 그려지는 것 |
|---|---|
avg | 모든 측정의 평균 곡선 하나 — 기기의 "대표" 선입니다. |
curves | 각 측정을 개별 곡선으로. UI에서 하나씩 켜고 끌 수 있습니다. |
fill | 모든 측정을 감싸는 최소/최대 음영 밴드 — 편차 포락선입니다. |
샘플 세트는 variants 배열 안에서 variant별로 선언합니다.
{
"name": ["HD 600"],
"variants": [
{ "suffix": "Stock", "file": "HD600 Stock" },
{ "suffix": "Modded", "file": "HD600 Mod", "samples": 5 },
{
"suffix": "Leather Pad",
"file": "HD600 Leather",
"samples": {
"count": 5,
"labels": ["Center", "Front", "Back", "Up", "Down"],
"display": ["avg", "fill"],
"description": "(Positional Variance)"
}
},
{
"suffix": "Suede Pad",
"samples": {
"files": ["Suede Center", "Suede Front", "Suede Back"],
"labels": ["Center", "Front", "Back"],
"display": ["fill", "curves"]
}
}
]
}
variants의 각 항목이 받는 키:
suffix(문자열, 선택) — 기기 선택기 드롭다운에 표시되는 variant 라벨.file(문자열, 선택) — 대표 L/R 쌍의 기본 파일 이름 —{file} L.txt/{file} R.txt.samples.files로 측정 파일을 직접 나열한다면 생략해도 됩니다.samples(숫자 또는 객체, 선택) — 샘플 세트. 숫자만 쓰면{ "count": n }의 축약형입니다.
samples를 객체로 쓸 때의 키:
count(숫자) — 측정 횟수.{file} L1.txt…L{count}.txt와 대응하는R파일을 로드합니다. CrinGraph의num_samples사이트가 이미 쓰고 있는 파일 배치입니다.files(문자열 배열) — 측정별 기본 파일 이름.{name} L.txt와{name} R.txt를 로드합니다.count와 함께 쓰지 말고 둘 중 하나만 쓰세요.labels(문자열 배열, 선택) — 측정별 표시 이름. 샘플 선택기와 그래프 라벨에 나타납니다(예:HD 600 Leather Pad (Center, R)). 생략하면files값이,count형식에서는 "Sample 1", "Sample 2"… 가 쓰입니다.display(문자열 배열, 선택) —avg,curves,fill의 조합. 초기 토글 상태를 정할 뿐이고 사용자는 여전히 곡선별로 바꿀 수 있습니다. 생략하면config.js의SAMPLES.DEFAULT_DISPLAY를 따릅니다.description(문자열, 선택) — 무엇이 달라지는지 설명하는 짧은 메모로, 기기 이름 옆에 표시됩니다(예:"(Fit Position)","(Rig Variance)","(Insertion Depth)").
count와 files의 차이는 파일 이름 규칙일 뿐이며 기능 차이가 아닙니다. 라벨,
음영, 개별 곡선은 어느 쪽에서도 똑같이 동작합니다.
file과 함께 동작합니다variants는 phone 레벨의 file / suffix / prefix / samples / hptfs 키를
대체하지 않습니다. 두 형식은 하나의 variant 목록으로 합쳐집니다. file이 이미
선언된 측정을 가리키는 항목은 그 variant를 제자리에서 보강하며 순서를 유지하므로
phone의 기본 곡선이 바뀌지 않고, 그 외의 항목은 뒤에 추가됩니다. 따라서 같은
variant를 양쪽에 선언해도 목록에는 한 번만 나타납니다.
덕분에 하나의 항목으로 두 도구를 모두 지원할 수 있습니다. CrinGraph는 file만 읽기
때문에, 측정이 variants에만 선언된 phone은 CrinGraph에서 보이지 않습니다. 일반
측정은 file / suffix에 두고 그 위에 sample set을 얹으세요.
{
"name": ["Soloist"],
"file": ["Soloist Stock", "Soloist Starline", "Soloist SpinFit"],
"prefix": "Soloist",
"variants": [
{
"suffix": "Insertion Depth",
"samples": {
"files": ["Soloist Starline 7k", "Soloist Starline", "Soloist Starline 9k"],
"labels": ["7 kHz", "8 kHz", "9 kHz"],
"display": ["avg", "fill"]
}
}
]
}
CrinGraph에는 이어팁 variant 3개가, modernGraphTool에는 그 3개에 더해 삽입 깊이
sample set이 표시됩니다. 항목을 하나 더 늘리는 대신 특정 이어팁에 측정 반복을 붙이고
싶다면, 해당 variant의 file을 그 이어팁의 파일 이름으로 지정하면 제자리에서
보강됩니다.
count 형식에서 {file} L1.txt / {file} R1.txt를 찾지 못하면 첫 번째 측정에
한해 번호 없는 {file} L.txt / {file} R.txt 쌍으로 폴백합니다. 덕분에 형제
variant끼리 번호 있는 파일과 없는 파일을 자유롭게 섞을 수 있고, 번호 파일이 없는
variant도 오류 없이 로드됩니다.
config.js의 SAMPLES.DEFAULT_COUNT와 SAMPLES.DEFAULT_DISPLAY는 자체 세트를
선언하지 않은 모든 variant에 적용됩니다. 모든 기기를 다섯 번씩 측정하는
데이터베이스라면 항목마다 samples를 적을 필요가 전혀 없습니다. 브랜드 단위로는 name 옆에
defaultSamples를 두어 그 브랜드의 기기에만 다른 기본값을 줄 수 있습니다.
SAMPLES 설정 섹션을 참고하세요.
간략 형식: phone 레벨 samples: N
variants 배열 없이, phone의 모든 file[] variant에 같은 측정 횟수를 한 번에
지정할 수 있습니다.
{ "name": ["Multi Sample"], "file": ["Multi Sample"], "samples": 3 }
"variants": [{ "file": "Multi Sample", "samples": 3 }]과 동등합니다. 이 형식은
계속 지원됩니다. phone 항목의 나머지 부분과 마찬가지로 CrinGraph 호환 구조를
공유하므로, 다른 도구용으로 작성한 phone_book.json도 그대로 동작합니다. 다만
한계가 있고, 그 한계가 variants가 존재하는 이유입니다. phone의 모든 variant가 같은
측정 횟수를 공유해야 하고, 측정별 라벨도 음영도 쓸 수 없습니다.
사용 중단: hptfs[]
hptfs[]는 편차 세트를 위해 modernGraphTool이 자체적으로 만든 키였고, 이제
variants[]가 그 역할을 모두 대신합니다. 이 키는 사용 중단(deprecated)되었으며
향후 릴리스에서 제거될 예정입니다. 지금은 계속 읽히므로 업그레이드하는 순간
깨지지는 않지만, 새로 hptfs[] 항목을 작성하지 말고 편한 시점에 phone book을
변환해 두세요.
samples: N과 달리 CrinGraph 생태계의 다른 도구는 hptfs[]를 읽지 않으므로,
제거해도 호환성에 손해가 없습니다.
{
"name": ["HpTF Multi Pad"],
"hptfs": [
{
"suffix": "Leather Pad",
"files": ["Leather Center", "Leather Front", "Leather Back"],
"labels": ["Center", "Front", "Back"],
"description": "(Leather Pad Variance)",
"fillOnly": false
}
]
}
위 항목은 samples.files와 display: ["avg", "fill"]을 가진 variants 항목이
됩니다. fillOnly가 false이면 여기에 "curves"가 추가됩니다.
{
"name": ["HpTF Multi Pad"],
"variants": [
{
"suffix": "Leather Pad",
"samples": {
"files": ["Leather Center", "Leather Front", "Leather Back"],
"labels": ["Center", "Front", "Back"],
"display": ["avg", "fill", "curves"],
"description": "(Leather Pad Variance)"
}
}
]
}
직접 손으로 고칠 필요는 없습니다. 기존 phone_book.json을
phone_book.json 편집기에 불러온 뒤 다시 내보내면 됩니다.
불러오기는 모든 이전 형식을 읽고, 내보내기는 항상 표준 형식인 variants[]로
작성합니다. hptfs[] 항목을 포함해 파일 전체가 한 번에 변환됩니다.
config.js의 MULTI_SAMPLE, HPTF 섹션도 함께 사용 중단되었습니다. 대체 키는
SAMPLES를 참고하세요.
한 phone 항목의 일반 file / suffix variant, phone 레벨 samples, hptfs 항목,
variants 항목은 한 평면 목록에서 각각 독립된 variant로 취급됩니다. file
variant 2개와 hptfs 항목 2개가 있으면 variant 선택기에 4개 항목이 표시됩니다.
예외는 위에서 설명한 제자리 보강뿐입니다. 이미 선언된 file을 가리키는 variants
항목은 새 항목을 만들지 않고 그 variant를 보강합니다.
두 부분 모두 문제없이 공유할 수 있습니다.
- 측정 폴더 — 라벨, 음영, 개별 곡선 설정은 번호 파일 위에 얹히는 부가
메타데이터입니다.
count를 쓰는 데이터베이스는 CrinGraph의num_samples사이트가 기대하는{file} L{n}.txt배치를 그대로 유지하므로 폴더 하나로 두 도구를 모두 서비스할 수 있습니다. phone_book.json— CrinGraph가 읽는 것은file뿐이므로 일반 측정은 모두file/suffix에 두고, sample set은 그 옆에variants로 추가하세요. CrinGraph는 모르는 키를 무시하고, modernGraphTool은 둘을 합쳐서 보여줍니다.
측정 데이터 추가/수정 절차
- 새 Phone 측정 파일(.txt)을
data/phones폴더에 복사합니다. - 텍스트 에디터로
phone_book.json을 엽니다. - JSON 문법에 맞춰 새 Phone 정보를 추가하거나 기존 정보를 수정합니다.
phone_book.json을 저장합니다.- 웹 페이지를 새로고침해서 변경 사항이 잘 반영됐는지 확인합니다.
phone_book.json을 수정할 때는 JSON 문법(따옴표, 쉼표 등)을 정확히 지켜야 합니다. 오류가 있으면 페이지가 정상적으로 로드되지 않습니다. VS Code의 빨간색·주황색 오류 표시 기능을 함께 활용하면 문법 실수를 미리 잡기 쉽습니다.