@@ -616,9 +616,14 @@ if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
616616 const float f_gain = (float )gain / (oversampling << 1 );
617617 size_t src_idx = ~0u ;
618618 size_t src_len = 0 ;
619- int32_t sum_value[4 ] = { 0 ,0 };
619+ int32_t sum_value[2 ] = { 0 , 0 };
620620 int32_t prev_value[2 ] = { 0 , 0 };
621621 const bool in_stereo = self->_cfg .stereo ;
622+ // A mono capture step yields two time steps. When a buffer fills after
623+ // the first one, the second is kept here for the next pending request so
624+ // back-to-back recordings stay continuous whatever their length.
625+ int32_t carry_value = 0 ;
626+ bool carry_valid = false ;
622627 int32_t os_remain = oversampling;
623628 const size_t dma_buf_len = self->_cfg .dma_buf_len ;
624629 // / dma_buf_len は DMA descriptor のフレーム数として使われる (_setup_i2s の
@@ -666,9 +671,62 @@ if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
666671 src_len = 0 ;
667672 sum_value[0 ] = 0 ;
668673 sum_value[1 ] = 0 ;
674+ carry_valid = false ; // buffered input is dropped here as well; the carry is only for back-to-back requests
669675 os_remain = oversampling;
670676 continue ;
671677 }
678+
679+ // Write one element in the request's sample format.
680+ auto write_one = [&](int32_t value)
681+ {
682+ if (current_rec->is_16bit )
683+ {
684+ if ( value < INT16_MIN +16 ) { value = INT16_MIN +16 ; }
685+ else if (value > INT16_MAX -16 ) { value = INT16_MAX -16 ; }
686+ auto dst = (int16_t *)(current_rec->data );
687+ *dst++ = value;
688+ current_rec->data = dst;
689+ }
690+ else
691+ {
692+ value = ((value + 128 ) >> 8 ) + 128 ;
693+ if ( value < 0 ) { value = 0 ; }
694+ else if (value > 255 ) { value = 255 ; }
695+ auto dst = (uint8_t *)(current_rec->data );
696+ *dst++ = value;
697+ current_rec->data = dst;
698+ }
699+ --dst_remain;
700+ };
701+ // Write one time step (left, right). A mono request takes left only
702+ // (the caller has already averaged a stereo capture); a stereo request
703+ // whose last element is reached after left drops right, so an odd
704+ // stereo length ends with a lone left sample.
705+ auto write_step = [&](int32_t left, int32_t right)
706+ {
707+ write_one (left);
708+ if (current_rec->is_stereo && dst_remain) { write_one (right); }
709+ };
710+ auto release_current = [&](void )
711+ {
712+ // data has been walked forward while filling: step back over the
713+ // whole buffer to hand the caller the pointer they gave record().
714+ const size_t total = current_rec->length .load (std::memory_order_relaxed);
715+ void * released = (uint8_t *)current_rec->data - total * (current_rec->is_16bit ? 2 : 1 );
716+ current_rec->length .store (0 , std::memory_order_release);
717+ xSemaphoreGive (self->_task_semaphore );
718+ if (self->_cb_buffer_release )
719+ {
720+ self->_cb_buffer_release (self->_cb_buffer_release_args , released, total);
721+ }
722+ };
723+
724+ if (carry_valid)
725+ {
726+ carry_valid = false ;
727+ write_step (carry_value, carry_value);
728+ if (dst_remain == 0 ) { release_current (); continue ; }
729+ }
672730 for (;;)
673731 {
674732 if (src_idx >= src_len)
@@ -747,61 +805,22 @@ if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
747805 }
748806 }
749807
750- int output_num = 2 ;
751-
752- if (in_stereo != current_rec->is_stereo )
753- {
754- if (in_stereo)
755- { // stereo -> mono convert.
756- sum_value[0 ] = (sum_value[0 ] + sum_value[1 ] + 1 ) >> 1 ;
757- output_num = 1 ;
758- }
759- else
760- { // mono -> stereo convert.
761- auto tmp = sum_value[1 ];
762- sum_value[3 ] = tmp;
763- sum_value[2 ] = tmp;
764- sum_value[1 ] = sum_value[0 ];
765- output_num = 4 ;
766- }
808+ if (in_stereo)
809+ { // one time step (L, R); a mono request takes the average
810+ if (current_rec->is_stereo ) { write_step (sum_value[0 ], sum_value[1 ]); }
811+ else { write_one ((sum_value[0 ] + sum_value[1 ] + 1 ) >> 1 ); }
767812 }
768- for (int i = 0 ; i < output_num; ++i)
769- {
770- auto value = sum_value[i];
771- if (current_rec->is_16bit )
772- {
773- if ( value < INT16_MIN +16 ) { value = INT16_MIN +16 ; }
774- else if (value > INT16_MAX -16 ) { value = INT16_MAX -16 ; }
775- auto dst = (int16_t *)(current_rec->data );
776- *dst++ = value;
777- current_rec->data = dst;
778- }
779- else
780- {
781- value = ((value + 128 ) >> 8 ) + 128 ;
782- if ( value < 0 ) { value = 0 ; }
783- else if (value > 255 ) { value = 255 ; }
784- auto dst = (uint8_t *)(current_rec->data );
785- *dst++ = value;
786- current_rec->data = dst;
787- }
813+ else
814+ { // two time steps; a stereo request duplicates each into L and R
815+ write_step (sum_value[0 ], sum_value[0 ]);
816+ if (dst_remain) { write_step (sum_value[1 ], sum_value[1 ]); }
817+ else { carry_value = sum_value[1 ]; carry_valid = true ; }
788818 }
789819 sum_value[0 ] = 0 ;
790820 sum_value[1 ] = 0 ;
791- dst_remain -= output_num;
792- if ((int32_t )dst_remain <= 0 )
821+ if (dst_remain == 0 )
793822 {
794- // data has been walked forward while filling: step back over what
795- // was written to hand the caller the pointer they gave record().
796- const size_t total = current_rec->length .load (std::memory_order_relaxed);
797- const size_t written = total - dst_remain; // dst_remain may have wrapped below 0
798- void * released = (uint8_t *)current_rec->data - written * (current_rec->is_16bit ? 2 : 1 );
799- current_rec->length .store (0 , std::memory_order_release);
800- xSemaphoreGive (self->_task_semaphore );
801- if (self->_cb_buffer_release )
802- {
803- self->_cb_buffer_release (self->_cb_buffer_release_args , released, total);
804- }
823+ release_current ();
805824 break ;
806825 }
807826 }
@@ -1065,6 +1084,9 @@ if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
10651084 // From the release callback (the capture task itself) nothing may be
10661085 // waited for: an end() holding _rec_lock waits for this task to exit, and
10671086 // a free slot only comes from this task. Try once and report.
1087+ // Nothing to record into is a caller error, not a request: it used to
1088+ // return true without ever invoking the release callback.
1089+ if (recdata == nullptr || array_len == 0 ) { return false ; }
10681090 const bool in_task = (xTaskGetCurrentTaskHandle () == _task_handle.load (std::memory_order_acquire));
10691091 for (;;)
10701092 {
@@ -1090,7 +1112,6 @@ if (_cfg.pin_bck < 0 || _cfg.pin_ws < 0) {
10901112 {
10911113 int res = _begin_raw (sample_rate);
10921114 if (res <= 0 ) { return res; }
1093- if (array_len == 0 ) { return 1 ; }
10941115 // Any free slot will do: the consume order comes from the sequence
10951116 // number stamped below, not from which slot a request lands in. A full
10961117 // queue just means "come back later".
0 commit comments