diff --git a/1000-hours/.vitepress/config.mts b/1000-hours/.vitepress/config.mts index 8455ae49..4a8155c9 100644 --- a/1000-hours/.vitepress/config.mts +++ b/1000-hours/.vitepress/config.mts @@ -226,8 +226,12 @@ export default withMermaid( link: "/sounds-of-american-english/4.3-group", }, { - text: "4.4. 句子", - link: "/sounds-of-american-english/4.4-sentences", + text: "4.4. 连接", + link: "/sounds-of-american-english/4.4-linking", + }, + { + text: "4.5. 句子", + link: "/sounds-of-american-english/4.5-sentences", }, ], }, diff --git a/1000-hours/public/audios/A-woman,-without-her,-man-is-nothing.-nova.mp3 b/1000-hours/public/audios/A-woman,-without-her,-man-is-nothing.-nova.mp3 new file mode 100644 index 00000000..ebb23cc1 Binary files /dev/null and b/1000-hours/public/audios/A-woman,-without-her,-man-is-nothing.-nova.mp3 differ diff --git a/1000-hours/public/audios/A-woman-without-her-man-is-nothing.-alloy.mp3 b/1000-hours/public/audios/A-woman-without-her-man-is-nothing.-alloy.mp3 new file mode 100644 index 00000000..817f21a6 Binary files /dev/null and b/1000-hours/public/audios/A-woman-without-her-man-is-nothing.-alloy.mp3 differ diff --git a/1000-hours/public/audios/Let's-eat-kids.-alloy.mp3 b/1000-hours/public/audios/Let's-eat-kids.-alloy.mp3 new file mode 100644 index 00000000..13a8af0e Binary files /dev/null and b/1000-hours/public/audios/Let's-eat-kids.-alloy.mp3 differ diff --git a/1000-hours/public/audios/Let's-eat...-kids.-alloy.mp3 b/1000-hours/public/audios/Let's-eat...-kids.-alloy.mp3 new file mode 100644 index 00000000..1756e829 Binary files /dev/null and b/1000-hours/public/audios/Let's-eat...-kids.-alloy.mp3 differ diff --git a/1000-hours/public/audios/hotdog-us-female.mp3 b/1000-hours/public/audios/hotdog-us-female.mp3 new file mode 100644 index 00000000..cd86c34f Binary files /dev/null and b/1000-hours/public/audios/hotdog-us-female.mp3 differ diff --git a/1000-hours/public/audios/hotdog-us-male.mp3 b/1000-hours/public/audios/hotdog-us-male.mp3 new file mode 100644 index 00000000..4080f0d9 Binary files /dev/null and b/1000-hours/public/audios/hotdog-us-male.mp3 differ diff --git a/1000-hours/public/audios/network-us-female.mp3 b/1000-hours/public/audios/network-us-female.mp3 new file mode 100644 index 00000000..a55c3a78 Binary files /dev/null and b/1000-hours/public/audios/network-us-female.mp3 differ diff --git a/1000-hours/public/audios/network-us-male.mp3 b/1000-hours/public/audios/network-us-male.mp3 new file mode 100644 index 00000000..0cc67617 Binary files /dev/null and b/1000-hours/public/audios/network-us-male.mp3 differ diff --git a/1000-hours/public/jupyter-notebooks/edge-tts-valcab-pronounciation.ipynb b/1000-hours/public/jupyter-notebooks/edge-tts-valcab-pronounciation.ipynb index 5ca36b08..3d5e8c7e 100644 --- a/1000-hours/public/jupyter-notebooks/edge-tts-valcab-pronounciation.ipynb +++ b/1000-hours/public/jupyter-notebooks/edge-tts-valcab-pronounciation.ipynb @@ -29,7 +29,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 2, "id": "71d35cd9", "metadata": {}, "outputs": [ @@ -37,19 +37,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "['en-US-GuyNeural', 'en-US-AriaNeural']\n", - "hello\n", - "../audios/hello-us-male.mp3 created\n", - "../audios/hello-us-female.mp3 created\n", - "\n", - "heat\n", - "../audios/heat-us-male.mp3 created\n", - "../audios/heat-us-female.mp3 created\n", - "\n", - "high\n", - "../audios/high-us-male.mp3 created\n", - "../audios/high-us-female.mp3 created\n", - "\n" + "pygame 2.6.0 (SDL 2.28.4, Python 3.12.2)\n", + "Hello from the pygame community. https://www.pygame.org/contribute.html\n" ] } ], @@ -84,10 +73,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "id": "4146f92e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['en-US-GuyNeural', 'en-US-AriaNeural']\n", + "apple\n", + "../audios/apple-us-male.mp3 exists, skipping...\n", + "../audios/apple-us-female.mp3 exists, skipping...\n", + "\n", + "impossible\n", + "../audios/impossible-us-male.mp3 exists, skipping...\n", + "../audios/impossible-us-female.mp3 exists, skipping...\n", + "\n", + "possible\n", + "../audios/possible-us-male.mp3 created\n", + "../audios/possible-us-female.mp3 created\n", + "\n", + "ichthyosaur\n", + "../audios/ichthyosaur-us-male.mp3 created\n", + "../audios/ichthyosaur-us-female.mp3 created\n", + "\n" + ] + } + ], "source": [ "\n", "voices = [\"en-US-GuyNeural\", \"en-US-AriaNeural\", \"en-GB-RyanNeural\", \"en-GB-LibbyNeural\"]\n", @@ -101,9 +114,11 @@ " print(voices)\n", "\n", "words = \"\"\"\n", - "hello,\n", - "heat,\n", - "high,\n", + "apple,\n", + "impossible,\n", + "possible,\n", + "ichthyosaur,\n", + "\n", "\"\"\"\n", "\n", "for word in words.strip().split(','):\n", @@ -117,10 +132,18 @@ }, { "cell_type": "code", - "execution_count": 63, + "execution_count": 15, "id": "2d46cde4", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a-woman--without-her--man-is-nothing_openai.mp3\n" + ] + } + ], "source": [ "def get_openai_tts_audio(text, path, performer='alloy'):\n", " \n", @@ -137,12 +160,14 @@ " ) as response:\n", " response.stream_to_file(path)\n", " \n", - "sentence = \"The explanation you gave was clear but I need a more detailed explanation.\"\n", + "sentence = \"A woman..., without her..., man is nothing.\"\n", "\n", "# remove all punctuation at the end of sentence,\n", "# replace all spaces and punctuations in the sentence with dash\n", - "audio_filename_openai = sentence.translate(str.maketrans(' ,.?!', '-----')).strip().replace(\"--\", \"-\") + '_openai.mp3'\n", - "audio_filename_msedge = sentence.translate(str.maketrans(' ,.?!', '-----')).strip().replace(\"--\", \"-\") + '_msedge.mp3'\n", + "audio_filename_openai = sentence.strip().translate(str.maketrans(',.?! ', '-----')).replace(\"--\", \"-\").lower().rstrip('-') + '_openai.mp3'\n", + "audio_filename_msedge = sentence.strip().translate(str.maketrans(',.?! ', '-----')).replace(\"--\", \"-\").lower().rstrip('-') + '_msedge.mp3'\n", + "\n", + "print(audio_filename_openai)\n", "# get_openai_tts_audio(sentence, audio_filename_openai, performer='alloy')\n", "# await generate_edge_tts_audio(sentence, audio_filename_msedge, voice=\"en-US-GuyNeural\", verbose=True, overwrite=True, play=True)\n", "\n", diff --git a/1000-hours/public/videos/yet-it-is-a-fact-of-life.mp4 b/1000-hours/public/videos/yet-it-is-a-fact-of-life.mp4 index 9c6cde72..3c630e24 100644 Binary files a/1000-hours/public/videos/yet-it-is-a-fact-of-life.mp4 and b/1000-hours/public/videos/yet-it-is-a-fact-of-life.mp4 differ diff --git a/1000-hours/sounds-of-american-english/4.3-group.md b/1000-hours/sounds-of-american-english/4.3-group.md index dfea2575..97bb9a61 100644 --- a/1000-hours/sounds-of-american-english/4.3-group.md +++ b/1000-hours/sounds-of-american-english/4.3-group.md @@ -1,4 +1,71 @@ # 4.2. 意群 -在自然语流中,很多句子并不是 “一口气” 读完的 —— 句子常常会被分割为若干个**意群**。 +在自然语流中,很多句子并不是 “一口气” 读完的…… +## 4.2.1. 意群 + +**句子**,只要略微长一点,就可能会被分割为若干个**意群**。 + +先听听以下视频里的这段话,同时观察一下语音的 “波谱”(*waveform*)及其 “音高变化”(*pitch contour*): + +> Yet, it is a fact of life that an unlettered peasant is considered ignorant.[^1] +> + +从波谱可以清晰地看到,这一整句话,显然被分成了 3 个**意群**: + +> * Yet, +> * it is a fact of life +> * that an unlettered peasant is considered ignorant. + +> [!Note] +> 这个视频截取自 [Enjoy App](https://1000h.org/enjoy-app/)。Enjoy 是一个英语学习工具(及其社区)。我们可以用它分析任何语音文件,清楚地看到 “停顿” 或者 “声调” 之类过去我们仅用听力难以完整分别的细节…… + +事实上,如果你反复多听几遍,你会发现,*peasant* 这个词,ˈpez.ənt 是这样读出来的:ˈpez.ən 之后有个很细微的停顿(stop),而后 t 与后面的 ɪz 连了起来…… 本质上,这是因为这个 t 的舌尖动作完整,然后有个停顿,而后接着说出了后面的 ɪz,所以它们才听起来被连起来了。 + +无论是**暂停**(pause)还是**停顿**(stop),虽然它们没有声音,却都在自然语流中都起着重要的作用。 + +为了将来的说明清楚与方便,我们会将意群之间的语流空隙称为 “**停**”(或者 “**暂停**”,即,*pause*),而把词汇内音节之间的语流空隙称为 “**顿**”(或者 “**停顿**”,即,*stop*)。 + +> * **停**(**暂停**/*pause*):发生在意群之间,语流空隙时段较长,可以用来换气,不会产生 “连读” 现象 +> * **顿**(**停顿**/*stop*):发生在音节之间,语流空隙时段很短(但的确存在),不会用来换气,前后可能产生 “连读现象 + +## 4.2.2. 停/暂停(pause) + +暂停的作用就是 “断句” —— 英文和中文一样的,其实任何语言也都是如此,不同的断句,有可能造成意义或者逻辑的变化。 + +> * Let's eat, kids. +> * Let's eat kids. + +或者 + +> * A woman without her man is nothing. +> * A woman: without her, man is nothing. + +而同一意群中细微的**停顿**(*stop*)影响自然语流的节奏,不符合惯常节奏的声音,总是需要 “多一层的处理” 才能够理解。 + +## 4.2.3. 顿/停顿(stop) + +**暂停/停**(*pause*)往往很容易分辨,但,**停顿**(*stop*)就是几乎被所有初学者完全忽视的重要细节。 + +一个常见的停顿来自于**重读音节**。当我们想要强调某个音节的时候,为了能把它读得相对较重,在此之前往往需要**停顿**一下 —— 做个准备。 + +比如,你可以试着读一下 *absolutely* ˌæbsəˈluːtli…… 为了把 luː 这个音节读成**重音**(顺带说,这是个长元音),你可能就会不由自主地在发出 之后略微**停顿**一下…… 拿之前的例子 *individual* ˌɪndəˈvɪdʒuəl 再试一下,若是在 之前略微**停顿**一下,就能相对更为轻松地将它读成**重音**。 + +另外一个更为常见的**停顿**相对比较微妙,它就在那里,可不仅听不到,就算说话的人就在眼前,也看不到他们停顿时的发声器官的具体动作。 + +比如,在 *hotdog* ˈhɑːt.dɑːɡ这个词里,t 的声音是听不到的,但,它的舌尖动作却是**完整**的,所以,能够听到的不是 ˈhɑtˌdɔg,也不是 ˈhɑˌdɔg,而是 ˈhɑt̚ ˌdɔg。你可以再试试 *network* ˈnetˌwərk 这个词 —— 这里面的 t 也是同样的机制。(注意,也有人用喉塞音 ʔ 读这这两个词中的 t。) + +这类**停顿**(*stop*),也叫**塞音**,最常见的有以下几种: + +> - 唇塞音(*Bilabial stop*):pbmfv —— *I just cannot hel**p** myself*. 第四个单词 help 末尾的 p 就是一个唇塞音。 +> - 齿塞音(*Dental stop*):θð —— *I wish the pa**th** to success was smoother.* 第四个单词 pæθ 末尾的 θ 就是一个齿塞音。 +> - 龈塞音(*Alveolar stop*): td —— *He trie**d** to discuss his idea with his boss.* 第二个单词 traɪd 末尾的 d 就是一个龈塞音。 +> - 喉塞音(*Glottal stop*):k, g, t —— IPA 里用 ʔ标注。 *I don't thin**k** that is true.* 第三个单词 *think* 末尾的 k 就是一个喉塞音,θɪŋʔ ðæt。 *uh-oh* ɑʔoʊ 是另外一个例子…… t 也有可能用这个喉塞音,比如,*utmost* ˈʌʔˌmoʊst,或者 ˈneʔwɝːk。 + +不管是哪一种,都是因为那个辅音**虽然并未发出声音,但整个发声器官却动作完整**而形成的。 + +这是一个非常重要的建议: + +> 在研究 “**连读**” 之前,可能更应该先仔细研究 “**停**与**顿**”。 + +[^1]: 这段语音截取自 [Thomas Sowell](https://en.wikipedia.org/wiki/Thomas_Sowell) 的 [Knowledge and Decisions](https://www.amazon.com/Knowledge-Decisions-Thomas-Sowell-ebook/dp/B09NKRSC3W/) 有声版(Audible) diff --git a/1000-hours/sounds-of-american-english/4.4-sentences.md b/1000-hours/sounds-of-american-english/4.4-linking.md similarity index 100% rename from 1000-hours/sounds-of-american-english/4.4-sentences.md rename to 1000-hours/sounds-of-american-english/4.4-linking.md diff --git a/1000-hours/sounds-of-american-english/4.5-sentences.md b/1000-hours/sounds-of-american-english/4.5-sentences.md new file mode 100644 index 00000000..e69de29b