परियोजना की मांग सी में एक प्रोग्राम लिखने की है जो ध्वनि के डेटा को केवल getchar के साथ इनपुट से wav प्रारूप/टेम्पलेट के अनुसार पढ़ता है।
प्रोग्राम को यह जांचना चाहिए कि दिया गया डेटा सही है या नहीं। जब पहली गलती का पता चलता है तो एक उपयुक्त संदेश प्रकट होता है और प्रोग्राम बंद हो जाता है। सरणियों, कार्यों, बिंदुओं और गणितीय पुस्तकालयों का उपयोग निषिद्ध है। यह भी जांचता है कि क्या हमारे पास अपर्याप्त डेटा या खराब फ़ाइल आकार है।

तरंग फ़ाइल स्वरूप:
http://tiny.systems/software/soundProgrammer/WavFormatDocs.pdf http://www.topherlee.com/software/pcm-tut-wavformat.html

उदाहरण मैंने सोचा कि यह कोड संख्या पढ़ने के लिए है:

while ( (ch = getchar()) != '\n') 
{
    if (ch >= '0' && ch <= '9')
    {
        bytes_sec = 10 * bytes_sec  + (ch - '0');
    }
}
fprintf(stderr, "bytes/sec:%d\n", bytes_sec);

लेकिन यह सही नहीं है क्योंकि हम चाहते हैं कि संख्या एक बाइट के रूप में सहेजी जाए।

और पात्रों के लिए मैंने यह कोड सोचा:

flag = 0;
fores = 0;

while ( ( (ch=getchar()) !='\n') && (flag==0)  ) {
    fores = fores + 1;
    if  (fores == 1) {
        if (ch != 'R')
        {
            flag = 1;
        }
    }
    else if (fores == 2) {
        if (ch != 'I')
            {
                flag = 1;
            }
    }
    else if (fores == 3) {
        if (ch!='F') {
                flag = 1;
            }
    }
    else {
        if ((fores != 4) || (ch != 'F')) {
            flag = 1;
        }
    }
}

if (flag == 1) {
    fprintf(stderr, "Error! \"RIFF\" not found\n");
    return 0;
}

मुझे यह भी समझ में नहीं आया कि डेटा किस रूप (बाइनरी, हेक्स, दशमलव) में दिया गया है (मुझे पता है कि WAV प्रारूप में डेटा बाइनरी में है लेकिन मैं अभी भी समझ नहीं पा रहा हूं कि डेटा के रूप में वास्तव में क्या दिया गया है और कैसे - फॉर्म और यदि इसे एक टुकड़े के रूप में या अलग से दिया जाता है)।
अंत में तथ्य यह है कि हम टर्मिनल डेटा में प्रवेश नहीं कर सकते हैं जो प्रिंट करने योग्य वर्णों के अनुरूप नहीं है, वास्तव में मुझे भ्रमित करता है।

मान लें कि हमारे पास कानूनी WAV फ़ाइल (हेक्स) की सामग्री है:

0000000 52 49 46 46 85 00 00 00 57 41 56 45 66 6d 74 20
0000020 10 00 00 00 01 00 01 00 44 ac 00 00 88 58 01 00
0000040 02 00 10 00 64 61 74 61 58 00 00 00 00 00 d4 07
0000060 a1 0f 5e 17 04 1f 8a 26 ea 2d 1c 35 18 3c d7 42
0000100 54 49 86 4f 69 55 f6 5a 27 60 f8 64 63 69 64 6d
0000120 f7 70 18 74 c5 76 fa 78 b6 7a f6 7b b9 7c ff 7c
0000140 c8 7c 12 7c e0 7a 33 79 0b 77 6c 74 58 71 d1 6d
0000160 dd 69 7e 65 b8 60 92 5b 0f 56 36 50 0c 4a 97 43
0000200 df 3c ea 35 45 78 74 72 61 44 61 74 61
0000215

मैंने सोचा कि इसे हेक्स से दशमलव में बदलने के लिए और फिर कमांड fopen(fname, "rb") का उपयोग करने के लिए डेटा फ़ाइल बनाने के लिए नोटपैड का उपयोग करें, लेकिन फिर मुझे पॉइंटर का उपयोग करना होगा जो प्रतिबंधित है। इसलिए मुझे अभी भी समझ में नहीं आया है कि प्रोग्राम को इनपुट पर मूल्य/मूल्य कैसे मिलेंगे।

इसके अलावा @AndreasWenzel के सुझावों के बाद मैं इस कोड के साथ छोटे-एंडियन के लिए आया (नोट: while में स्थिति गलत है, इसे सी कंपाइलर में जांचना आसान होने के लिए चुना गया है):

#include <stdio.h>

int ch, sample_rate, help, fores, sum, i;
int main()
{
    fores = 0;
    sample_rate = 0;
    
    while ( (ch = getchar()) != '\n' )
    {
            help = (ch - '0');
            fprintf(stderr, "help:%d\n", help);
            if (help == 1)
            {
                sum = 1;
                for (i=1 ; i<=fores ; i++)
                {
                    sum = sum*2;
                }
                sample_rate = sample_rate + (sum);
                fprintf(stderr, "sample:%d\n", sample_rate);
            }
            fores = fores + 1;
    }
fprintf(stderr, "sample rate:%d\n", sample_rate);
}

यदि हमारे पास इनपुट के रूप में 10100100 (बाइनरी) = 164 (दशमलव) है तो यह 37 (दशमलव) प्रिंट करेगा। क्या यह सही है?

1
W44 10 जिंदा 2021, 17:45

1 उत्तर

सबसे बढ़िया उत्तर

पूर्णांक कैसे होते हैं, इस पर स्पष्टीकरण के लिए यह लिंक देखें बाइनरी में संग्रहीत होने पर स्मृति में दर्शाया जाता है। ध्यान दें कि इस कार्य के लिए, आपको स्मृति में हस्ताक्षरित पूर्णांकों का प्रतिनिधित्व करने के तरीके के बारे में पढ़ने की ज़रूरत नहीं है (आपको केवल अहस्ताक्षरित के बारे में जानने की आवश्यकता है), और आपको यह भी पढ़ने की ज़रूरत नहीं है कि स्मृति में फ़्लोटिंग-पॉइंट संख्याओं का प्रतिनिधित्व कैसे किया जाता है।

RIFF फ़ाइल (जैसे .wav फ़ाइल) में, अधिकांश डेटा ASCII< में संग्रहीत नहीं होता है /a>, लेकिन बाइनरी में। RIFF फ़ाइल में केवल बहुत कम चीज़ें ASCII में संग्रहीत होती हैं। उदाहरण के लिए, (उप-) चंक हेडर में प्रत्येक में 4-बाइट आईडी होती है, जैसे RIFF, fmt , जो ASCII में संग्रहीत है। लेकिन संख्याओं को लगभग कभी भी '0' से '9' वर्णों के ASCII एन्कोडिंग में संग्रहीत नहीं किया जाएगा, जैसा कि आपका कोड लगता है।

बाइनरी फ़ाइल पढ़ते समय, while स्थिति

(ch=getchar()) !='\n'

बात नहीं बनी। ऐसी अभिव्यक्ति केवल लाइन-सीमांकित टेक्स्ट इनपुट के साथ समझ में आती है। बाइनरी फ़ाइल में, मान '\n', जो कि न्यूलाइन कैरेक्टर के ASCII एन्कोडिंग का मान है, का कोई विशेष अर्थ नहीं है। यह किसी भी अन्य की तरह सिर्फ एक बाइट मान है, जो संयोग से बाइनरी फ़ाइल में हो सकता है, उदाहरण के लिए किसी संख्या के बाइनरी प्रतिनिधित्व में।

इसलिए, RIFF ChunkID की जांच करने के लिए, आपके while लूप को हमेशा फ़ाइल से ठीक 4 बाइट्स पढ़ना चाहिए। इसे तब तक पढ़ना जारी नहीं रखना चाहिए जब तक कि इसे '\n' न मिल जाए, जैसा कि अभी है।

बाद के ChunkSize मान को पढ़ने के लिए, जो 4 बाइट लंबा है, आपको ठीक 4 बाइट्स फिर से पढ़ना चाहिए। आपके पास uint_least32_t प्रकार का एक वेरिएबल भी होना चाहिए, जो एक अहस्ताक्षरित पूर्णांक है और इसकी लंबाई कम से कम 32 बिट होने की गारंटी है। यह सुनिश्चित करता है कि ChunkSize को स्टोर करने के लिए चर आकार में पर्याप्त है। फिर आप getchar का उपयोग करके एक बार में एक बाइट पढ़ सकते हैं और फिर अलग-अलग बाइट्स के मानों का उपयोग करके पूरी संख्या की गणना कर सकते हैं। व्यक्तिगत बाइट मानों से बड़ी संख्या की गणना कैसे करें, यह समझने के लिए कंप्यूटर मेमोरी में पूर्णांकों का प्रतिनिधित्व कैसे किया जाता है, इसके बारे में उपरोक्त लिंक देखें। होमवर्क प्रश्नों पर इन नियमों के अनुसार, मैं इस समस्या का समाधान नहीं दूंगा, जब तक कि आप विशेष रूप से इसके लिए नहीं कहते यह। तब तक, मैं केवल निम्नलिखित संकेत प्रदान करूंगा:

  • आपको इस बात का ध्यान रखना चाहिए कि नंबर little-endian बाइट ऑर्डरिंग में संग्रहित है।
  • getchar के साथ पढ़ते समय, आपको परिणाम को int या unsigned char में संग्रहित करना चाहिए, न कि signed char या char (जो अधिकांश प्लेटफॉर्म पर हस्ताक्षरित है) . अन्यथा, चर का मान ऋणात्मक होगा, यदि बाइट का मान 127 से बड़ा है। ऐसे नकारात्मक मानों के साथ काम करना कठिन है।

ध्यान दें कि यदि आप #include <windows.h> का उपयोग कर रहे हैं (और आप एक ऐसे प्लेटफ़ॉर्म पर हैं जिसमें यह हेडर है), तो आप uint_least32_t के बजाय टाइपिफ़ DWORD का उपयोग कर सकते हैं। यदि आप uint_least32_t का उपयोग कर रहे हैं, तो आपको #include <stdint.h> करना होगा।


संपादित करें: अब जब आपने समस्या को स्वयं हल कर लिया है, तो मैं अपना वैकल्पिक समाधान प्रदान करूंगा। हालाँकि, कार्य सरणियों, बिंदुओं और उपयोगकर्ता-परिभाषित कार्यों के उपयोग को मना करता है। दूसरी ओर, मेरी राय में, इन प्रतिबंधों का सम्मान करने वाली समस्या के सभी समाधान गड़बड़ होंगे और उनमें बड़ी मात्रा में अनावश्यक कोड दोहराव होगा। इसलिए, मैंने उन्हें अपने समाधान में उपयोग किया है, जो इन प्रतिबंधों का सम्मान नहीं करता है:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>

//This will print an error message if you attempt to compile this 
//on a platform on which there are not 8 bits per byte.
#if CHAR_BIT != 8
#error "This program assumes 8 bits per byte."
#endif

void VerifyLabel( const char *label );
uint_fast32_t ReadNumber( int num_bytes, const char *fieldname );

int main( void )
{
    uint_fast32_t temp;

    VerifyLabel( "RIFF" );

    ReadNumber( 4, "ChunkSize" );

    VerifyLabel( "WAVE" );

    VerifyLabel( "fmt " );

    temp =
        ReadNumber( 4, "Subchunk1Size" );

    if ( temp != 16 )
    {
        fprintf( stderr, "Error: Expected Subchunk1Size to be 16!\n" );
        exit( EXIT_FAILURE );
    }

    temp =
        ReadNumber( 2, "AudioFormat" );

    if ( temp != 1 )
    {
        fprintf( stderr, "Error: Expected AudioFormat to be 1 (PCM)!\n" );
        exit( EXIT_FAILURE );
    }

    temp =
        ReadNumber( 2, "NumChannels" );

    if ( temp != 1 && temp != 2 )
    {
        fprintf( stderr, "Error: Expected NumChannels to be 1 (mono) or 2 (stereo)!\n" );
        exit( EXIT_FAILURE );
    }

    ReadNumber( 4, "SampleRate" );

    ReadNumber( 4, "ByteRate" );

    ReadNumber( 2, "BlockAlign" );

    temp =
        ReadNumber( 2, "BitePerSample" );

    if ( temp != 8 && temp != 16 )
    {
        fprintf( stderr, "Error: Expected BitsPerSample to be 8 or 16!\n" );
        exit( EXIT_FAILURE );
    }

    VerifyLabel( "data" );

    ReadNumber( 4, "Subchunk2Size" );

    return 0;
}

void VerifyLabel( const char *label )
{
    for ( const char *p = label; *p != '\0'; p++ )
    {
        int c;

        if ( (c = getchar()) == EOF )
        {
            fprintf( stderr, "input error while verifying \"%s\" label!\n", label );
            exit( EXIT_FAILURE );
        }

        if ( (uint_fast8_t)*p != c )
        {
            fprintf( stderr, "did not find \"%s\" label in expected position!\n", label );
            exit( EXIT_FAILURE );
        }
    }

    fprintf( stderr, "\"%s\" label OK\n", label );
}

uint_fast32_t ReadNumber( int num_bytes, const char *fieldname )
{
    int c;

    uint_fast32_t sum = 0;

    if ( num_bytes < 1 || num_bytes > 4 )
    {
        fprintf( stderr, "this function only supports reading between 1 and 4 bytes\n" );
        exit( EXIT_FAILURE );
    }

    for ( int i = 0; i < num_bytes; i++ )
    {
        if ( (c = getchar()) == EOF )
        {
            fprintf( stderr, "input error while reading field \"%s\"!\n", fieldname );
            exit( EXIT_FAILURE );
        }

        sum += (uint_fast8_t)c << 8 * i;
    }

    //On most platforms, unsigned int is 32-bits. On those platforms, the following
    //line is equivalent to:
    //fprintf( stderr, "%s: %u\n", fieldname, sum );
    fprintf( stderr, "%s: %" PRIuFAST32 "\n", fieldname, sum );

    return sum;
}

यह मेरे कार्यक्रम का नमूना आउटपुट है:

"RIFF" label OK
ChunkSize: 88236
"WAVE" label OK
"fmt " label OK
Subchunk1Size: 16
AudioFormat: 1
NumChannels: 1
SampleRate: 44100
ByteRate: 44100
BlockAlign: 1
BitePerSample: 8
"data" label OK
Subchunk2Size: 88200
1
Andreas Wenzel 19 जिंदा 2021, 08:06
आपके समय और आपने मुझे जो सहायता प्रदान की उसके लिए धन्यवाद! यदि आप एक बार देखना चाहते हैं तो मूल पोस्ट को अपडेट/संपादित कर लिया है। अगर आपको लगता है कि कुछ बेहतर है या मेरे दृष्टिकोण में कोड के साथ समझाया जाना चाहिए तो स्वीकार्य/स्वागत है। मैंने जो भाग वर्णित किया है वह पूरी परियोजना का केवल 1/7 है इसलिए कोड के साथ एक छोटा सा स्पष्टीकरण मुझे नहीं लगता कि इससे कोई नुकसान होगा। आप जो कुछ भी अधिक उपयुक्त या उत्पादक समझते हैं, उसे करने के लिए स्वतंत्र महसूस करें।
 – 
W44
11 जिंदा 2021, 13:04
@ W44: आपके अपडेट में, आपने लिखा था: "नोट: स्थिति गलत है, इसे एसी कंपाइलर में जांचना आसान होने के लिए चुना गया है" - मुझे समझ में नहीं आता कि आप उपयोग जारी रखते हुए क्या हासिल करना चाहते हैं '\n', क्योंकि, जैसा कि मैंने अपने उत्तर में पहले ही समझाया है, बाइनरी फ़ाइल में वह मान अर्थहीन है।
 – 
Andreas Wenzel
12 जिंदा 2021, 06:17
@W44: help=(ch - '0'); का क्या मतलब है? एएससीआईआई में एन्कोड किए गए अंकों का मूल्यांकन करते समय वह अभिव्यक्ति केवल सार्थक होगी, जहां आपके पास प्रति बाइट एक अंक है। हालाँकि, RIFF फ़ाइल में, अधिकांश संख्याएँ ASCII में प्रदर्शित नहीं होती हैं, लेकिन बाइनरी में संग्रहीत होती हैं। द्विआधारी प्रतिनिधित्व में, एक बाइट 0 और 255 (जो 0x00 से 0xFF हेक्साडेसिमल प्रतिनिधित्व में है) के बीच की संख्या का प्रतिनिधित्व कर सकता है। और 4 बाइट्स, जब एक नंबर को स्टोर करने के लिए एक साथ उपयोग किया जाता है, तो 0 और 4,294,967,295 के बीच की संख्या का प्रतिनिधित्व कर सकता है। यह सब मेरे द्वारा पोस्ट किए गए लिंक में समझाया गया है।
 – 
Andreas Wenzel
12 जिंदा 2021, 06:27
@ W44: ध्यान दें कि आपके द्वारा पोस्ट की गई फ़ाइल का हेक्साडेसिमल दृश्य टेक्स्ट है, बाइनरी नहीं। यह अलग-अलग बाइट्स के मान दिखाता है, इसलिए ऐसा हेक्साडेसिमल दृश्य बाइनरी फ़ाइलों की सामग्री को दिखाने के लिए अच्छा है। लेकिन आपको वास्तविक बाइनरी डेटा के साथ बाइनरी फ़ाइल के ऐसे हेक्साडेसिमल टेक्स्ट प्रस्तुतिकरण को भ्रमित नहीं करना चाहिए। ऐसे हेक्साडेसिमल टेक्स्ट प्रस्तुतिकरण को पार्स करना वास्तविक बाइनरी डेटा को पार्स करने जैसा ही नहीं है।
 – 
Andreas Wenzel
12 जिंदा 2021, 06:35
@ W44: यह भी ध्यान दें कि प्रोग्राम notepad.exe बाइनरी फ़ाइलें बनाने में असमर्थ है। यह टेक्स्ट फाइल बनाने के लिए है। बाइनरी फ़ाइलें बनाने के लिए, आपको एक तथाकथित "हेक्स संपादक" प्रोग्राम का उपयोग करना होगा (या उन्हें अपने प्रोग्राम के साथ बनाएं)। कुछ पाठ संपादकों में एक "बाइनरी" या "हेक्स" मोड होता है जो आपको बाइनरी मोड में संपादन करने की अनुमति देता है, लेकिन अधिकांश नहीं (नोटपैड सहित)।
 – 
Andreas Wenzel
12 जिंदा 2021, 06:51