mirror of
https://github.com/Tony0410/News-reader-pro.git
synced 2026-05-24 21:31:44 +08:00
Sets up the foundational elements for the NewsCaster AI application. This includes: - Initializing the project with Vite and React. - Defining core types for articles and player state. - Configuring build tools and TypeScript. - Adding essential dependencies like React, Vite, and Google's Gemini API client. - Providing initial README instructions for running locally. - Setting up basic styling and structure in index.html. - Defining available voices and playback constants. - Implementing utility functions for audio handling.
59 lines
1.9 KiB
TypeScript
59 lines
1.9 KiB
TypeScript
/**
|
|
* Converts a Base64 string (Raw PCM) to a Uint8Array.
|
|
*/
|
|
export const base64ToUint8Array = (base64: string): Uint8Array => {
|
|
const binaryString = atob(base64);
|
|
const len = binaryString.length;
|
|
const bytes = new Uint8Array(len);
|
|
for (let i = 0; i < len; i++) {
|
|
bytes[i] = binaryString.charCodeAt(i);
|
|
}
|
|
return bytes;
|
|
};
|
|
|
|
/**
|
|
* Wraps raw PCM data in a WAV container so it can be played by standard HTML5 Audio elements.
|
|
* This allows us to use `playbackRate` with automatic pitch preservation.
|
|
*/
|
|
export const createWavBlob = (pcmData: Uint8Array, sampleRate: number = 24000): Blob => {
|
|
const numChannels = 1;
|
|
const bitsPerSample = 16;
|
|
const byteRate = (sampleRate * numChannels * bitsPerSample) / 8;
|
|
const blockAlign = (numChannels * bitsPerSample) / 8;
|
|
const dataSize = pcmData.length;
|
|
const chunkSize = 36 + dataSize;
|
|
|
|
const buffer = new ArrayBuffer(44 + dataSize);
|
|
const view = new DataView(buffer);
|
|
|
|
// RIFF chunk descriptor
|
|
writeString(view, 0, 'RIFF');
|
|
view.setUint32(4, chunkSize, true);
|
|
writeString(view, 8, 'WAVE');
|
|
|
|
// fmt sub-chunk
|
|
writeString(view, 12, 'fmt ');
|
|
view.setUint32(16, 16, true); // Subchunk1Size (16 for PCM)
|
|
view.setUint16(20, 1, true); // AudioFormat (1 for PCM)
|
|
view.setUint16(22, numChannels, true); // NumChannels
|
|
view.setUint32(24, sampleRate, true); // SampleRate
|
|
view.setUint32(28, byteRate, true); // ByteRate
|
|
view.setUint16(32, blockAlign, true); // BlockAlign
|
|
view.setUint16(34, bitsPerSample, true); // BitsPerSample
|
|
|
|
// data sub-chunk
|
|
writeString(view, 36, 'data');
|
|
view.setUint32(40, dataSize, true);
|
|
|
|
// Write PCM data
|
|
const dataView = new Uint8Array(buffer, 44);
|
|
dataView.set(pcmData);
|
|
|
|
return new Blob([buffer], { type: 'audio/wav' });
|
|
};
|
|
|
|
const writeString = (view: DataView, offset: number, string: string) => {
|
|
for (let i = 0; i < string.length; i++) {
|
|
view.setUint8(offset + i, string.charCodeAt(i));
|
|
}
|
|
}; |